diff --git a/FinalSecurityApp/.gitignore b/FinalSecurityApp/.gitignore new file mode 100644 index 00000000..549e00a2 --- /dev/null +++ b/FinalSecurityApp/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/FinalSecurityApp/.mvn/wrapper/MavenWrapperDownloader.java b/FinalSecurityApp/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 00000000..e76d1f32 --- /dev/null +++ b/FinalSecurityApp/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/FinalSecurityApp/.mvn/wrapper/maven-wrapper.jar b/FinalSecurityApp/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 00000000..2cc7d4a5 Binary files /dev/null and b/FinalSecurityApp/.mvn/wrapper/maven-wrapper.jar differ diff --git a/FinalSecurityApp/.mvn/wrapper/maven-wrapper.properties b/FinalSecurityApp/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..ffdc10e5 --- /dev/null +++ b/FinalSecurityApp/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/FinalSecurityApp/mvnw b/FinalSecurityApp/mvnw new file mode 100755 index 00000000..a16b5431 --- /dev/null +++ b/FinalSecurityApp/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/FinalSecurityApp/mvnw.cmd b/FinalSecurityApp/mvnw.cmd new file mode 100644 index 00000000..c8d43372 --- /dev/null +++ b/FinalSecurityApp/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/FinalSecurityApp/pom.xml b/FinalSecurityApp/pom.xml new file mode 100644 index 00000000..204de392 --- /dev/null +++ b/FinalSecurityApp/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.1 + + + ru.alishev.springcourse + SpringSecurityApp + 0.0.1-SNAPSHOT + FirstSecurityApp + Spring Boot app with Spring Security + + 11 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-web + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity5 + + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityApp.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityApp.java new file mode 100644 index 00000000..bd055484 --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityApp.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.FirstSecurityApp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringSecurityApp { + + public static void main(String[] args) { + SpringApplication.run(SpringSecurityApp.class, args); + } + +} diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java new file mode 100644 index 00000000..56292f23 --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java @@ -0,0 +1,58 @@ +package ru.alishev.springcourse.FirstSecurityApp.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +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 ru.alishev.springcourse.FirstSecurityApp.services.PersonDetailsService; + +/** + * @author Neil Alishev + */ +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + private final PersonDetailsService personDetailsService; + + @Autowired + public SecurityConfig(PersonDetailsService personDetailsService) { + this.personDetailsService = personDetailsService; + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + // конфигурируем сам Spring Security + // конфигурируем авторизацию + http.authorizeRequests() + .antMatchers("/admin").hasRole("ADMIN") + .antMatchers("/auth/login", "/auth/registration", "/error").permitAll() + .anyRequest().hasAnyRole("USER", "ADMIN") + .and() + .formLogin().loginPage("/auth/login") + .loginProcessingUrl("/process_login") + .defaultSuccessUrl("/hello", true) + .failureUrl("/auth/login?error") + .and() + .logout() + .logoutUrl("/logout") + .logoutSuccessUrl("/auth/login"); + } + + // Настраиваем аутентификацию + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(personDetailsService) + .passwordEncoder(getPasswordEncoder()); + } + + @Bean + public PasswordEncoder getPasswordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/AuthController.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/AuthController.java new file mode 100644 index 00000000..421c14c6 --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/AuthController.java @@ -0,0 +1,54 @@ +package ru.alishev.springcourse.FirstSecurityApp.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +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; +import org.springframework.web.bind.annotation.RequestMapping; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; +import ru.alishev.springcourse.FirstSecurityApp.services.RegistrationService; +import ru.alishev.springcourse.FirstSecurityApp.util.PersonValidator; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/auth") +public class AuthController { + + private final RegistrationService registrationService; + private final PersonValidator personValidator; + + @Autowired + public AuthController(RegistrationService registrationService, PersonValidator personValidator) { + this.registrationService = registrationService; + this.personValidator = personValidator; + } + + @GetMapping("/login") + public String loginPage() { + return "auth/login"; + } + + @GetMapping("/registration") + public String registrationPage(@ModelAttribute("person") Person person) { + return "auth/registration"; + } + + @PostMapping("/registration") + public String performRegistration(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + personValidator.validate(person, bindingResult); + + if (bindingResult.hasErrors()) + return "/auth/registration"; + + registrationService.register(person); + + return "redirect:/auth/login"; + } +} diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java new file mode 100644 index 00000000..2792d860 --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java @@ -0,0 +1,42 @@ +package ru.alishev.springcourse.FirstSecurityApp.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import ru.alishev.springcourse.FirstSecurityApp.security.PersonDetails; +import ru.alishev.springcourse.FirstSecurityApp.services.AdminService; + +/** + * @author Neil Alishev + */ +@Controller +public class HelloController { + private final AdminService adminService; + + @Autowired + public HelloController(AdminService adminService) { + this.adminService = adminService; + } + + @GetMapping("/hello") + public String sayHello() { + return "hello"; + } + + @GetMapping("/showUserInfo") + public String showUserInfo() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + PersonDetails personDetails = (PersonDetails) authentication.getPrincipal(); + System.out.println(personDetails.getPerson()); + + return "hello"; + } + + @GetMapping("/admin") + public String adminPage() { + adminService.doAdminStuff(); + return "admin"; + } +} diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java new file mode 100644 index 00000000..77f97f16 --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java @@ -0,0 +1,92 @@ +package ru.alishev.springcourse.FirstSecurityApp.models; + +import javax.persistence.*; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +@Entity +@Table(name = "Person") +public class Person { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @NotEmpty(message = "Имя не должно быть пустым") + @Size(min = 2, max = 100, message = "Имя должно быть от 2 до 100 символов длиной") + @Column(name = "username") + private String username; + + @Min(value = 1900, message = "Год рождения должен быть больше, чем 1900") + @Column(name = "year_of_birth") + private int yearOfBirth; + + @Column(name = "password") + private String password; + + @Column(name = "role") + private String role; + + // Конструктор по умолчанию нужен для Spring + public Person() { + } + + public Person(String username, int yearOfBirth) { + this.username = username; + this.yearOfBirth = yearOfBirth; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public int getYearOfBirth() { + return yearOfBirth; + } + + public void setYearOfBirth(int yearOfBirth) { + this.yearOfBirth = yearOfBirth; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", username='" + username + '\'' + + ", yearOfBirth=" + yearOfBirth + + ", password='" + password + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java new file mode 100644 index 00000000..569af7a4 --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java @@ -0,0 +1,15 @@ +package ru.alishev.springcourse.FirstSecurityApp.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; + +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Repository +public interface PeopleRepository extends JpaRepository { + Optional findByUsername(String username); +} diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java new file mode 100644 index 00000000..dc73b6e2 --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java @@ -0,0 +1,62 @@ +package ru.alishev.springcourse.FirstSecurityApp.security; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; + +import java.util.Collection; +import java.util.Collections; + +/** + * @author Neil Alishev + */ +public class PersonDetails implements UserDetails { + private final Person person; + + public PersonDetails(Person person) { + this.person = person; + } + + @Override + public Collection getAuthorities() { + // SHOW_ACCOUNT, WITHDRAW_MONEY, SEND_MONEY + // ROLE_ADMIN, ROLE_USER - это роли + return Collections.singletonList(new SimpleGrantedAuthority(person.getRole())); + } + + @Override + public String getPassword() { + return this.person.getPassword(); + } + + @Override + public String getUsername() { + return this.person.getUsername(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + // Нужно, чтобы получать данные аутентифицированного пользователя + public Person getPerson() { + return this.person; + } +} diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/AdminService.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/AdminService.java new file mode 100644 index 00000000..545e4374 --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/AdminService.java @@ -0,0 +1,16 @@ +package ru.alishev.springcourse.FirstSecurityApp.services; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Service; + +/** + * @author Neil Alishev + */ +@Service +public class AdminService { + + @PreAuthorize("hasRole('ROLE_ADMIN') and hasRole('ROLE_SOME_OTHER')") + public void doAdminStuff() { + System.out.println("Only admin here"); + } +} diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java new file mode 100644 index 00000000..4ca5432a --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java @@ -0,0 +1,36 @@ +package ru.alishev.springcourse.FirstSecurityApp.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; +import ru.alishev.springcourse.FirstSecurityApp.repositories.PeopleRepository; +import ru.alishev.springcourse.FirstSecurityApp.security.PersonDetails; + +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Service +public class PersonDetailsService implements UserDetailsService { + + private final PeopleRepository peopleRepository; + + @Autowired + public PersonDetailsService(PeopleRepository peopleRepository) { + this.peopleRepository = peopleRepository; + } + + @Override + public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { + Optional person = peopleRepository.findByUsername(s); + + if (person.isEmpty()) + throw new UsernameNotFoundException("User not found"); + + return new PersonDetails(person.get()); + } +} diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/RegistrationService.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/RegistrationService.java new file mode 100644 index 00000000..38cb0eec --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/RegistrationService.java @@ -0,0 +1,31 @@ +package ru.alishev.springcourse.FirstSecurityApp.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; +import ru.alishev.springcourse.FirstSecurityApp.repositories.PeopleRepository; + +/** + * @author Neil Alishev + */ +@Service +public class RegistrationService { + + private final PeopleRepository peopleRepository; + private final PasswordEncoder passwordEncoder; + + @Autowired + public RegistrationService(PeopleRepository peopleRepository, PasswordEncoder passwordEncoder) { + this.peopleRepository = peopleRepository; + this.passwordEncoder = passwordEncoder; + } + + @Transactional + public void register(Person person) { + person.setPassword(passwordEncoder.encode(person.getPassword())); + person.setRole("ROLE_USER"); + peopleRepository.save(person); + } +} diff --git a/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/util/PersonValidator.java b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/util/PersonValidator.java new file mode 100644 index 00000000..93694cc9 --- /dev/null +++ b/FinalSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/util/PersonValidator.java @@ -0,0 +1,41 @@ +package ru.alishev.springcourse.FirstSecurityApp.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; +import ru.alishev.springcourse.FirstSecurityApp.services.PersonDetailsService; + +/** + * @author Neil Alishev + */ +@Component +public class PersonValidator implements Validator { + + private final PersonDetailsService personDetailsService; + + @Autowired + public PersonValidator(PersonDetailsService personDetailsService) { + this.personDetailsService = personDetailsService; + } + + @Override + public boolean supports(Class aClass) { + return Person.class.equals(aClass); + } + + @Override + public void validate(Object o, Errors errors) { + Person person = (Person) o; + + try { + personDetailsService.loadUserByUsername(person.getUsername()); + } catch (UsernameNotFoundException ignored) { + return; // все ок, пользователь не найден + } + + errors.rejectValue("username", "", "Человек с таким именем пользователя уже существует"); + } +} diff --git a/FinalSecurityApp/src/main/resources/application.properties b/FinalSecurityApp/src/main/resources/application.properties new file mode 100644 index 00000000..ffd7c456 --- /dev/null +++ b/FinalSecurityApp/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/security_app_db +spring.datasource.username=postgres +spring.datasource.password=postgres + +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.show_sql=true \ No newline at end of file diff --git a/FinalSecurityApp/src/main/resources/templates/admin.html b/FinalSecurityApp/src/main/resources/templates/admin.html new file mode 100644 index 00000000..4e64e0a1 --- /dev/null +++ b/FinalSecurityApp/src/main/resources/templates/admin.html @@ -0,0 +1,10 @@ + + + + + Admin page + + +Admin page + + \ No newline at end of file diff --git a/FinalSecurityApp/src/main/resources/templates/auth/login.html b/FinalSecurityApp/src/main/resources/templates/auth/login.html new file mode 100644 index 00000000..f1cc287e --- /dev/null +++ b/FinalSecurityApp/src/main/resources/templates/auth/login.html @@ -0,0 +1,26 @@ + + + + + Login page + + + +
+ + + + +
+ + +
+ + +
+ Неправильные имя или пароль +
+
+ + + \ No newline at end of file diff --git a/FinalSecurityApp/src/main/resources/templates/auth/registration.html b/FinalSecurityApp/src/main/resources/templates/auth/registration.html new file mode 100644 index 00000000..990ab437 --- /dev/null +++ b/FinalSecurityApp/src/main/resources/templates/auth/registration.html @@ -0,0 +1,27 @@ + + + + + Registration + + + +
+ + +
Username Error
+
+ + +
Year of birth Error +
+
+ + +
Password Error
+
+ +
+ + + \ No newline at end of file diff --git a/FinalSecurityApp/src/main/resources/templates/hello.html b/FinalSecurityApp/src/main/resources/templates/hello.html new file mode 100644 index 00000000..b5f49686 --- /dev/null +++ b/FinalSecurityApp/src/main/resources/templates/hello.html @@ -0,0 +1,14 @@ + + + + + Hello + + +Hello world! +
+ +
+ + + \ No newline at end of file diff --git a/FinalSecurityApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityAppTests.java b/FinalSecurityApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityAppTests.java new file mode 100644 index 00000000..ffd4aff2 --- /dev/null +++ b/FinalSecurityApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityAppTests.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.FirstSecurityApp; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringSecurityAppTests { + + @Test + void contextLoads() { + } + +} diff --git a/FirstRestApp/.gitignore b/FirstRestApp/.gitignore new file mode 100644 index 00000000..549e00a2 --- /dev/null +++ b/FirstRestApp/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/FirstRestApp/.mvn/wrapper/MavenWrapperDownloader.java b/FirstRestApp/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 00000000..e76d1f32 --- /dev/null +++ b/FirstRestApp/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/FirstRestApp/.mvn/wrapper/maven-wrapper.jar b/FirstRestApp/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 00000000..2cc7d4a5 Binary files /dev/null and b/FirstRestApp/.mvn/wrapper/maven-wrapper.jar differ diff --git a/FirstRestApp/.mvn/wrapper/maven-wrapper.properties b/FirstRestApp/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..ffdc10e5 --- /dev/null +++ b/FirstRestApp/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/FirstRestApp/mvnw b/FirstRestApp/mvnw new file mode 100755 index 00000000..a16b5431 --- /dev/null +++ b/FirstRestApp/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/FirstRestApp/mvnw.cmd b/FirstRestApp/mvnw.cmd new file mode 100644 index 00000000..c8d43372 --- /dev/null +++ b/FirstRestApp/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/FirstRestApp/pom.xml b/FirstRestApp/pom.xml new file mode 100644 index 00000000..c3b8b9b3 --- /dev/null +++ b/FirstRestApp/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.3 + + + ru.alishev.springcourse + FirstRestApp + 0.0.1-SNAPSHOT + FirstRestApp + First REST Application + + 11 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/FirstRestAppApplication.java b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/FirstRestAppApplication.java new file mode 100644 index 00000000..64709ed0 --- /dev/null +++ b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/FirstRestAppApplication.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.FirstRestApp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FirstRestAppApplication { + + public static void main(String[] args) { + SpringApplication.run(FirstRestAppApplication.class, args); + } + +} diff --git a/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/controllers/FirstRESTController.java b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/controllers/FirstRESTController.java new file mode 100644 index 00000000..83d76bea --- /dev/null +++ b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/controllers/FirstRESTController.java @@ -0,0 +1,18 @@ +package ru.alishev.springcourse.FirstRestApp.controllers; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author Neil Alishev + */ +@RestController // @Controller + @ResponseBody над каждым методом +@RequestMapping("/api") +public class FirstRESTController { + + @GetMapping("/sayHello") + public String sayHello() { + return "Hello world!"; + } +} diff --git a/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/controllers/PeopleController.java b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/controllers/PeopleController.java new file mode 100644 index 00000000..f1257c60 --- /dev/null +++ b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/controllers/PeopleController.java @@ -0,0 +1,33 @@ +package ru.alishev.springcourse.FirstRestApp.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import ru.alishev.springcourse.FirstRestApp.models.Person; +import ru.alishev.springcourse.FirstRestApp.services.PeopleService; + +import java.util.List; + +/** + * @author Neil Alishev + */ +@RestController // @Controller + @ResponseBody над каждым методом +@RequestMapping("/people") +public class PeopleController { + + private final PeopleService peopleService; + + @Autowired + public PeopleController(PeopleService peopleService) { + this.peopleService = peopleService; + } + + @GetMapping() + public List getPeople() { + return peopleService.findAll(); // Jackson конвертирует эти объекты в JSON + } + + @GetMapping("/{id}") + public Person getPerson(@PathVariable("id") int id) { + return peopleService.findOne(id); // Jackson конвертирует в JSON + } +} diff --git a/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/models/Person.java b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/models/Person.java new file mode 100644 index 00000000..ef624530 --- /dev/null +++ b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/models/Person.java @@ -0,0 +1,65 @@ +package ru.alishev.springcourse.FirstRestApp.models; + +import javax.persistence.*; + +/** + * @author Neil Alishev + */ +@Entity +@Table(name = "Person") +public class Person { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @Column(name = "name") + private String name; + + @Column(name = "age") + private int age; + + @Column(name = "email") + private String email; + + public Person() { + + } + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/repositories/PeopleRepository.java b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/repositories/PeopleRepository.java new file mode 100644 index 00000000..9fdf805a --- /dev/null +++ b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/repositories/PeopleRepository.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.FirstRestApp.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.alishev.springcourse.FirstRestApp.models.Person; + +/** + * @author Neil Alishev + */ +@Repository +public interface PeopleRepository extends JpaRepository { + +} diff --git a/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/services/PeopleService.java b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/services/PeopleService.java new file mode 100644 index 00000000..6c2f3022 --- /dev/null +++ b/FirstRestApp/src/main/java/ru/alishev/springcourse/FirstRestApp/services/PeopleService.java @@ -0,0 +1,34 @@ +package ru.alishev.springcourse.FirstRestApp.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.alishev.springcourse.FirstRestApp.models.Person; +import ru.alishev.springcourse.FirstRestApp.repositories.PeopleRepository; + +import java.util.List; +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Service +@Transactional(readOnly = true) +public class PeopleService { + + private final PeopleRepository peopleRepository; + + @Autowired + public PeopleService(PeopleRepository peopleRepository) { + this.peopleRepository = peopleRepository; + } + + public List findAll() { + return peopleRepository.findAll(); + } + + public Person findOne(int id) { + Optional foundPerson = peopleRepository.findById(id); + return foundPerson.orElse(null); + } +} diff --git a/FirstRestApp/src/main/resources/application.properties b/FirstRestApp/src/main/resources/application.properties new file mode 100644 index 00000000..7090fe60 --- /dev/null +++ b/FirstRestApp/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/rest_app_db +spring.datasource.username=postgres +spring.datasource.password=postgres + +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.show_sql=true \ No newline at end of file diff --git a/FirstRestApp/src/test/java/ru/alishev/springcourse/FirstRestApp/FirstRestAppApplicationTests.java b/FirstRestApp/src/test/java/ru/alishev/springcourse/FirstRestApp/FirstRestAppApplicationTests.java new file mode 100644 index 00000000..246bf2ad --- /dev/null +++ b/FirstRestApp/src/test/java/ru/alishev/springcourse/FirstRestApp/FirstRestAppApplicationTests.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.FirstRestApp; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class FirstRestAppApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/FirstSecurityApp/.gitignore b/FirstSecurityApp/.gitignore new file mode 100644 index 00000000..549e00a2 --- /dev/null +++ b/FirstSecurityApp/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/FirstSecurityApp/.mvn/wrapper/MavenWrapperDownloader.java b/FirstSecurityApp/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 00000000..e76d1f32 --- /dev/null +++ b/FirstSecurityApp/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/FirstSecurityApp/.mvn/wrapper/maven-wrapper.jar b/FirstSecurityApp/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 00000000..2cc7d4a5 Binary files /dev/null and b/FirstSecurityApp/.mvn/wrapper/maven-wrapper.jar differ diff --git a/FirstSecurityApp/.mvn/wrapper/maven-wrapper.properties b/FirstSecurityApp/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..ffdc10e5 --- /dev/null +++ b/FirstSecurityApp/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/FirstSecurityApp/mvnw b/FirstSecurityApp/mvnw new file mode 100755 index 00000000..a16b5431 --- /dev/null +++ b/FirstSecurityApp/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/FirstSecurityApp/mvnw.cmd b/FirstSecurityApp/mvnw.cmd new file mode 100644 index 00000000..c8d43372 --- /dev/null +++ b/FirstSecurityApp/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/FirstSecurityApp/pom.xml b/FirstSecurityApp/pom.xml new file mode 100644 index 00000000..a6f56d93 --- /dev/null +++ b/FirstSecurityApp/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.1 + + + ru.alishev.springcourse + FirstSecurityApp + 0.0.1-SNAPSHOT + FirstSecurityApp + First Spring Boot app with Spring Security + + 11 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-web + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity5 + + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/FirstSecurityAppApplication.java b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/FirstSecurityAppApplication.java new file mode 100644 index 00000000..ab4341bf --- /dev/null +++ b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/FirstSecurityAppApplication.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.FirstSecurityApp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FirstSecurityAppApplication { + + public static void main(String[] args) { + SpringApplication.run(FirstSecurityAppApplication.class, args); + } + +} diff --git a/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java new file mode 100644 index 00000000..810ed071 --- /dev/null +++ b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java @@ -0,0 +1,26 @@ +package ru.alishev.springcourse.FirstSecurityApp.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import ru.alishev.springcourse.FirstSecurityApp.security.AuthProviderImpl; + +/** + * @author Neil Alishev + */ +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + private final AuthProviderImpl authProvider; + + @Autowired + public SecurityConfig(AuthProviderImpl authProvider) { + this.authProvider = authProvider; + } + + // Настраивает аутентификацию + protected void configure(AuthenticationManagerBuilder auth) { + auth.authenticationProvider(authProvider); + } +} diff --git a/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java new file mode 100644 index 00000000..c0432fb9 --- /dev/null +++ b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java @@ -0,0 +1,27 @@ +package ru.alishev.springcourse.FirstSecurityApp.controllers; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import ru.alishev.springcourse.FirstSecurityApp.security.PersonDetails; + +/** + * @author Neil Alishev + */ +@Controller +public class HelloController { + @GetMapping("/hello") + public String sayHello() { + return "hello"; + } + + @GetMapping("/showUserInfo") + public String showUserInfo() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + PersonDetails personDetails = (PersonDetails) authentication.getPrincipal(); + System.out.println(personDetails.getPerson()); + + return "hello"; + } +} diff --git a/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java new file mode 100644 index 00000000..b084d0c4 --- /dev/null +++ b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java @@ -0,0 +1,81 @@ +package ru.alishev.springcourse.FirstSecurityApp.models; + +import javax.persistence.*; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +@Entity +@Table(name = "Person") +public class Person { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @NotEmpty(message = "Имя не должно быть пустым") + @Size(min = 2, max = 100, message = "Имя должно быть от 2 до 100 символов длиной") + @Column(name = "username") + private String username; + + @Min(value = 1900, message = "Год рождения должен быть больше, чем 1900") + @Column(name = "year_of_birth") + private int yearOfBirth; + + @Column(name = "password") + private String password; + + // Конструктор по умолчанию нужен для Spring + public Person() { + } + + public Person(String username, int yearOfBirth) { + this.username = username; + this.yearOfBirth = yearOfBirth; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public int getYearOfBirth() { + return yearOfBirth; + } + + public void setYearOfBirth(int yearOfBirth) { + this.yearOfBirth = yearOfBirth; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", username='" + username + '\'' + + ", yearOfBirth=" + yearOfBirth + + ", password='" + password + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java new file mode 100644 index 00000000..569af7a4 --- /dev/null +++ b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java @@ -0,0 +1,15 @@ +package ru.alishev.springcourse.FirstSecurityApp.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; + +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Repository +public interface PeopleRepository extends JpaRepository { + Optional findByUsername(String username); +} diff --git a/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/AuthProviderImpl.java b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/AuthProviderImpl.java new file mode 100644 index 00000000..d4e0a346 --- /dev/null +++ b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/AuthProviderImpl.java @@ -0,0 +1,47 @@ +package ru.alishev.springcourse.FirstSecurityApp.security; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.FirstSecurityApp.services.PersonDetailsService; + +import java.util.Collections; + +/** + * @author Neil Alishev + */ +@Component +public class AuthProviderImpl implements AuthenticationProvider { + + private final PersonDetailsService personDetailsService; + + @Autowired + public AuthProviderImpl(PersonDetailsService personDetailsService) { + this.personDetailsService = personDetailsService; + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + String username = authentication.getName(); + + UserDetails personDetails = personDetailsService.loadUserByUsername(username); + + String password = authentication.getCredentials().toString(); + + if (!password.equals(personDetails.getPassword())) + throw new BadCredentialsException("Incorrect password"); + + return new UsernamePasswordAuthenticationToken(personDetails, password, + Collections.emptyList()); + } + + @Override + public boolean supports(Class aClass) { + return true; + } +} diff --git a/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java new file mode 100644 index 00000000..0c58f086 --- /dev/null +++ b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java @@ -0,0 +1,58 @@ +package ru.alishev.springcourse.FirstSecurityApp.security; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; + +import java.util.Collection; + +/** + * @author Neil Alishev + */ +public class PersonDetails implements UserDetails { + private final Person person; + + public PersonDetails(Person person) { + this.person = person; + } + + @Override + public Collection getAuthorities() { + return null; + } + + @Override + public String getPassword() { + return this.person.getPassword(); + } + + @Override + public String getUsername() { + return this.person.getUsername(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + // Нужно, чтобы получать данные аутентифицированного пользователя + public Person getPerson() { + return this.person; + } +} diff --git a/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java new file mode 100644 index 00000000..9d1d658b --- /dev/null +++ b/FirstSecurityApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java @@ -0,0 +1,36 @@ +package ru.alishev.springcourse.FirstSecurityApp.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; +import ru.alishev.springcourse.FirstSecurityApp.repositories.PeopleRepository; +import ru.alishev.springcourse.FirstSecurityApp.security.PersonDetails; + +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Service +public class PersonDetailsService implements UserDetailsService { + + private final PeopleRepository peopleRepository; + + @Autowired + public PersonDetailsService(PeopleRepository peopleRepository) { + this.peopleRepository = peopleRepository; + } + + @Override + public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { + Optional person = peopleRepository.findByUsername(s); + + if (person.isEmpty()) + throw new UsernameNotFoundException("User not found!"); + + return new PersonDetails(person.get()); + } +} diff --git a/FirstSecurityApp/src/main/resources/application.properties b/FirstSecurityApp/src/main/resources/application.properties new file mode 100644 index 00000000..ffd7c456 --- /dev/null +++ b/FirstSecurityApp/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/security_app_db +spring.datasource.username=postgres +spring.datasource.password=postgres + +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.show_sql=true \ No newline at end of file diff --git a/FirstSecurityApp/src/main/resources/templates/hello.html b/FirstSecurityApp/src/main/resources/templates/hello.html new file mode 100644 index 00000000..da114098 --- /dev/null +++ b/FirstSecurityApp/src/main/resources/templates/hello.html @@ -0,0 +1,10 @@ + + + + + Hello + + +Hello world! + + \ No newline at end of file diff --git a/FirstSecurityApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/FirstSecurityAppApplicationTests.java b/FirstSecurityApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/FirstSecurityAppApplicationTests.java new file mode 100644 index 00000000..4594b9fc --- /dev/null +++ b/FirstSecurityApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/FirstSecurityAppApplicationTests.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.FirstSecurityApp; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class FirstSecurityAppApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/HibernateApp/pom.xml b/HibernateApp/pom.xml new file mode 100644 index 00000000..31be59cc --- /dev/null +++ b/HibernateApp/pom.xml @@ -0,0 +1,89 @@ + + + + 4.0.0 + + org.example + HibernateApp + 1.0-SNAPSHOT + + HibernateApp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + + org.postgresql + postgresql + 42.2.19 + + + + + org.hibernate + hibernate-core + 5.4.28.Final + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + diff --git a/HibernateApp/src/main/java/org/example/App.java b/HibernateApp/src/main/java/org/example/App.java new file mode 100644 index 00000000..45970aee --- /dev/null +++ b/HibernateApp/src/main/java/org/example/App.java @@ -0,0 +1,31 @@ +package org.example; + +import org.example.model.Person; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; + +/** + * Hello world! + */ +public class App { + public static void main(String[] args) { + Configuration configuration = new Configuration().addAnnotatedClass(Person.class); + + SessionFactory sessionFactory = configuration.buildSessionFactory(); + Session session = sessionFactory.getCurrentSession(); + + try { + session.beginTransaction(); + + Person person = session.get(Person.class, 1); + System.out.println(person.getName()); + System.out.println(person.getAge()); + + session.getTransaction().commit(); + + } finally { + sessionFactory.close(); + } + } +} diff --git a/HibernateApp/src/main/java/org/example/model/Person.java b/HibernateApp/src/main/java/org/example/model/Person.java new file mode 100644 index 00000000..b24239c2 --- /dev/null +++ b/HibernateApp/src/main/java/org/example/model/Person.java @@ -0,0 +1,56 @@ +package org.example.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +/** + * @author Neil Alishev + */ +@Entity +@Table(name = "Person") +public class Person { + + @Id + @Column(name = "id") + private int id; + + @Column(name = "name") + private String name; + + @Column(name = "age") + private int age; + + public Person() {} + + public Person(int id, String name, int age) { + this.id = id; + this.name = name; + this.age = age; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} diff --git a/HibernateApp/src/main/resources/hibernate.properties b/HibernateApp/src/main/resources/hibernate.properties new file mode 100644 index 00000000..2c17e215 --- /dev/null +++ b/HibernateApp/src/main/resources/hibernate.properties @@ -0,0 +1,10 @@ +# Конфигурация источника данных (Data source) +hibernate.driver_class=org.postgresql.Driver +hibernate.connection.url=jdbc:postgresql://localhost:5432/hibernate_demo_db +hibernate.connection.username=postgres +hibernate.connection.password=postgres + +# Конфигурация самого Hibernate +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +hibernate.show_sql=true +hibernate.current_session_context_class=thread \ No newline at end of file diff --git a/HibernateApp/src/test/java/org/example/AppTest.java b/HibernateApp/src/test/java/org/example/AppTest.java new file mode 100644 index 00000000..6a1d2d79 --- /dev/null +++ b/HibernateApp/src/test/java/org/example/AppTest.java @@ -0,0 +1,20 @@ +package org.example; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +} diff --git a/JWTApp/.gitignore b/JWTApp/.gitignore new file mode 100644 index 00000000..549e00a2 --- /dev/null +++ b/JWTApp/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/JWTApp/.mvn/wrapper/MavenWrapperDownloader.java b/JWTApp/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 00000000..e76d1f32 --- /dev/null +++ b/JWTApp/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/JWTApp/.mvn/wrapper/maven-wrapper.jar b/JWTApp/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 00000000..2cc7d4a5 Binary files /dev/null and b/JWTApp/.mvn/wrapper/maven-wrapper.jar differ diff --git a/JWTApp/.mvn/wrapper/maven-wrapper.properties b/JWTApp/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..ffdc10e5 --- /dev/null +++ b/JWTApp/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/JWTApp/mvnw b/JWTApp/mvnw new file mode 100755 index 00000000..a16b5431 --- /dev/null +++ b/JWTApp/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/JWTApp/mvnw.cmd b/JWTApp/mvnw.cmd new file mode 100644 index 00000000..c8d43372 --- /dev/null +++ b/JWTApp/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/JWTApp/pom.xml b/JWTApp/pom.xml new file mode 100644 index 00000000..da23f253 --- /dev/null +++ b/JWTApp/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.1 + + + ru.alishev.springcourse + SpringSecurityApp + 0.0.1-SNAPSHOT + FirstSecurityApp + Spring Boot app with Spring Security + + 11 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-web + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity5 + + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + org.modelmapper + modelmapper + 3.0.0 + + + com.auth0 + java-jwt + 3.18.3 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityApp.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityApp.java new file mode 100644 index 00000000..b606a27a --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityApp.java @@ -0,0 +1,19 @@ +package ru.alishev.springcourse.FirstSecurityApp; + +import org.modelmapper.ModelMapper; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class SpringSecurityApp { + + public static void main(String[] args) { + SpringApplication.run(SpringSecurityApp.class, args); + } + + @Bean + public ModelMapper modelMapper() { + return new ModelMapper(); + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/JWTFilter.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/JWTFilter.java new file mode 100644 index 00000000..8d463e5b --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/JWTFilter.java @@ -0,0 +1,64 @@ +package ru.alishev.springcourse.FirstSecurityApp.config; + +import com.auth0.jwt.exceptions.JWTVerificationException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import ru.alishev.springcourse.FirstSecurityApp.security.JWTUtil; +import ru.alishev.springcourse.FirstSecurityApp.services.PersonDetailsService; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author Neil Alishev + */ +@Component +public class JWTFilter extends OncePerRequestFilter { + + private final JWTUtil jwtUtil; + private final PersonDetailsService personDetailsService; + + public JWTFilter(JWTUtil jwtUtil, PersonDetailsService personDetailsService) { + this.jwtUtil = jwtUtil; + this.personDetailsService = personDetailsService; + } + + @Override + protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { + String authHeader = httpServletRequest.getHeader("Authorization"); + + if (authHeader != null && !authHeader.isBlank() && authHeader.startsWith("Bearer ")) { + String jwt = authHeader.substring(7); + + if (jwt.isBlank()) { + httpServletResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, + "Invalid JWT Token in Bearer Header"); + } else { + try { + String username = jwtUtil.validateTokenAndRetrieveClaim(jwt); + UserDetails userDetails = personDetailsService.loadUserByUsername(username); + + UsernamePasswordAuthenticationToken authToken = + new UsernamePasswordAuthenticationToken(userDetails, + userDetails.getPassword(), + userDetails.getAuthorities()); + + if (SecurityContextHolder.getContext().getAuthentication() == null) { + SecurityContextHolder.getContext().setAuthentication(authToken); + } + } catch (JWTVerificationException exc) { + httpServletResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, + "Invalid JWT Token"); + } + } + } + + filterChain.doFilter(httpServletRequest, httpServletResponse); + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java new file mode 100644 index 00000000..9fac166b --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java @@ -0,0 +1,76 @@ +package ru.alishev.springcourse.FirstSecurityApp.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import ru.alishev.springcourse.FirstSecurityApp.services.PersonDetailsService; + +/** + * @author Neil Alishev + */ +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + private final PersonDetailsService personDetailsService; + private final JWTFilter jwtFilter; + + @Autowired + public SecurityConfig(PersonDetailsService personDetailsService, JWTFilter jwtFilter) { + this.personDetailsService = personDetailsService; + this.jwtFilter = jwtFilter; + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + // конфигурируем сам Spring Security + // конфигурируем авторизацию + http + .csrf().disable() + .authorizeRequests() + .antMatchers("/admin").hasRole("ADMIN") + .antMatchers("/auth/login", "/auth/registration", "/error").permitAll() + .anyRequest().hasAnyRole("USER", "ADMIN") + .and() + .formLogin().loginPage("/auth/login") + .loginProcessingUrl("/process_login") + .defaultSuccessUrl("/hello", true) + .failureUrl("/auth/login?error") + .and() + .logout() + .logoutUrl("/logout") + .logoutSuccessUrl("/auth/login") + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + + http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); + } + + // Настраиваем аутентификацию + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(personDetailsService) + .passwordEncoder(getPasswordEncoder()); + } + + @Bean + public PasswordEncoder getPasswordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/AuthController.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/AuthController.java new file mode 100644 index 00000000..e3e0d78d --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/AuthController.java @@ -0,0 +1,79 @@ +package ru.alishev.springcourse.FirstSecurityApp.controllers; + +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import ru.alishev.springcourse.FirstSecurityApp.dto.AuthenticationDTO; +import ru.alishev.springcourse.FirstSecurityApp.dto.PersonDTO; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; +import ru.alishev.springcourse.FirstSecurityApp.security.JWTUtil; +import ru.alishev.springcourse.FirstSecurityApp.services.RegistrationService; +import ru.alishev.springcourse.FirstSecurityApp.util.PersonValidator; + +import javax.validation.Valid; +import java.util.Map; + +/** + * @author Neil Alishev + */ +@RestController +@RequestMapping("/auth") +public class AuthController { + + private final RegistrationService registrationService; + private final PersonValidator personValidator; + private final JWTUtil jwtUtil; + private final ModelMapper modelMapper; + private final AuthenticationManager authenticationManager; + + @Autowired + public AuthController(RegistrationService registrationService, PersonValidator personValidator, + JWTUtil jwtUtil, ModelMapper modelMapper, AuthenticationManager authenticationManager) { + this.registrationService = registrationService; + this.personValidator = personValidator; + this.jwtUtil = jwtUtil; + this.modelMapper = modelMapper; + this.authenticationManager = authenticationManager; + } + + @PostMapping("/registration") + public Map performRegistration(@RequestBody @Valid PersonDTO personDTO, + BindingResult bindingResult) { + Person person = convertToPerson(personDTO); + + personValidator.validate(person, bindingResult); + + if (bindingResult.hasErrors()) { + return Map.of("message", "Ошибка!"); + } + + registrationService.register(person); + + String token = jwtUtil.generateToken(person.getUsername()); + return Map.of("jwt-token", token); + } + + @PostMapping("/login") + public Map performLogin(@RequestBody AuthenticationDTO authenticationDTO) { + UsernamePasswordAuthenticationToken authInputToken = + new UsernamePasswordAuthenticationToken(authenticationDTO.getUsername(), + authenticationDTO.getPassword()); + + try { + authenticationManager.authenticate(authInputToken); + } catch (BadCredentialsException e) { + return Map.of("message", "Incorrect credentials!"); + } + + String token = jwtUtil.generateToken(authenticationDTO.getUsername()); + return Map.of("jwt-token", token); + } + + public Person convertToPerson(PersonDTO personDTO) { + return this.modelMapper.map(personDTO, Person.class); + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java new file mode 100644 index 00000000..46d03e1b --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java @@ -0,0 +1,43 @@ +package ru.alishev.springcourse.FirstSecurityApp.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import ru.alishev.springcourse.FirstSecurityApp.security.PersonDetails; +import ru.alishev.springcourse.FirstSecurityApp.services.AdminService; + +/** + * @author Neil Alishev + */ +@Controller +public class HelloController { + private final AdminService adminService; + + @Autowired + public HelloController(AdminService adminService) { + this.adminService = adminService; + } + + @GetMapping("/hello") + public String sayHello() { + return "hello"; + } + + @GetMapping("/showUserInfo") + @ResponseBody + public String showUserInfo() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + PersonDetails personDetails = (PersonDetails) authentication.getPrincipal(); + + return personDetails.getUsername(); + } + + @GetMapping("/admin") + public String adminPage() { + adminService.doAdminStuff(); + return "admin"; + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/dto/AuthenticationDTO.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/dto/AuthenticationDTO.java new file mode 100644 index 00000000..f60cb05c --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/dto/AuthenticationDTO.java @@ -0,0 +1,31 @@ +package ru.alishev.springcourse.FirstSecurityApp.dto; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class AuthenticationDTO { + @NotEmpty(message = "Имя не должно быть пустым") + @Size(min = 2, max = 100, message = "Имя должно быть от 2 до 100 символов длиной") + private String username; + + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/dto/PersonDTO.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/dto/PersonDTO.java new file mode 100644 index 00000000..90d56540 --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/dto/PersonDTO.java @@ -0,0 +1,43 @@ +package ru.alishev.springcourse.FirstSecurityApp.dto; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class PersonDTO { + @NotEmpty(message = "Имя не должно быть пустым") + @Size(min = 2, max = 100, message = "Имя должно быть от 2 до 100 символов длиной") + private String username; + + @Min(value = 1900, message = "Год рождения должен быть больше, чем 1900") + private int yearOfBirth; + + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public int getYearOfBirth() { + return yearOfBirth; + } + + public void setYearOfBirth(int yearOfBirth) { + this.yearOfBirth = yearOfBirth; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java new file mode 100644 index 00000000..77f97f16 --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java @@ -0,0 +1,92 @@ +package ru.alishev.springcourse.FirstSecurityApp.models; + +import javax.persistence.*; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +@Entity +@Table(name = "Person") +public class Person { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @NotEmpty(message = "Имя не должно быть пустым") + @Size(min = 2, max = 100, message = "Имя должно быть от 2 до 100 символов длиной") + @Column(name = "username") + private String username; + + @Min(value = 1900, message = "Год рождения должен быть больше, чем 1900") + @Column(name = "year_of_birth") + private int yearOfBirth; + + @Column(name = "password") + private String password; + + @Column(name = "role") + private String role; + + // Конструктор по умолчанию нужен для Spring + public Person() { + } + + public Person(String username, int yearOfBirth) { + this.username = username; + this.yearOfBirth = yearOfBirth; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public int getYearOfBirth() { + return yearOfBirth; + } + + public void setYearOfBirth(int yearOfBirth) { + this.yearOfBirth = yearOfBirth; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", username='" + username + '\'' + + ", yearOfBirth=" + yearOfBirth + + ", password='" + password + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java new file mode 100644 index 00000000..569af7a4 --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java @@ -0,0 +1,15 @@ +package ru.alishev.springcourse.FirstSecurityApp.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; + +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Repository +public interface PeopleRepository extends JpaRepository { + Optional findByUsername(String username); +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/JWTUtil.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/JWTUtil.java new file mode 100644 index 00000000..c93ee6c6 --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/JWTUtil.java @@ -0,0 +1,44 @@ +package ru.alishev.springcourse.FirstSecurityApp.security; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTVerificationException; +import com.auth0.jwt.interfaces.DecodedJWT; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.time.ZonedDateTime; +import java.util.Date; + +/** + * @author Neil Alishev + */ +@Component +public class JWTUtil { + + @Value("${jwt_secret}") + private String secret; + + public String generateToken(String username) { + Date expirationDate = Date.from(ZonedDateTime.now().plusMinutes(60).toInstant()); + + return JWT.create() + .withSubject("User details") + .withClaim("username", username) + .withIssuedAt(new Date()) + .withIssuer("alishev") + .withExpiresAt(expirationDate) + .sign(Algorithm.HMAC256(secret)); + } + + public String validateTokenAndRetrieveClaim(String token) throws JWTVerificationException { + JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)) + .withSubject("User details") + .withIssuer("alishev") + .build(); + + DecodedJWT jwt = verifier.verify(token); + return jwt.getClaim("username").asString(); + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java new file mode 100644 index 00000000..dc73b6e2 --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java @@ -0,0 +1,62 @@ +package ru.alishev.springcourse.FirstSecurityApp.security; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; + +import java.util.Collection; +import java.util.Collections; + +/** + * @author Neil Alishev + */ +public class PersonDetails implements UserDetails { + private final Person person; + + public PersonDetails(Person person) { + this.person = person; + } + + @Override + public Collection getAuthorities() { + // SHOW_ACCOUNT, WITHDRAW_MONEY, SEND_MONEY + // ROLE_ADMIN, ROLE_USER - это роли + return Collections.singletonList(new SimpleGrantedAuthority(person.getRole())); + } + + @Override + public String getPassword() { + return this.person.getPassword(); + } + + @Override + public String getUsername() { + return this.person.getUsername(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + // Нужно, чтобы получать данные аутентифицированного пользователя + public Person getPerson() { + return this.person; + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/AdminService.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/AdminService.java new file mode 100644 index 00000000..545e4374 --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/AdminService.java @@ -0,0 +1,16 @@ +package ru.alishev.springcourse.FirstSecurityApp.services; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Service; + +/** + * @author Neil Alishev + */ +@Service +public class AdminService { + + @PreAuthorize("hasRole('ROLE_ADMIN') and hasRole('ROLE_SOME_OTHER')") + public void doAdminStuff() { + System.out.println("Only admin here"); + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java new file mode 100644 index 00000000..4ca5432a --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java @@ -0,0 +1,36 @@ +package ru.alishev.springcourse.FirstSecurityApp.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; +import ru.alishev.springcourse.FirstSecurityApp.repositories.PeopleRepository; +import ru.alishev.springcourse.FirstSecurityApp.security.PersonDetails; + +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Service +public class PersonDetailsService implements UserDetailsService { + + private final PeopleRepository peopleRepository; + + @Autowired + public PersonDetailsService(PeopleRepository peopleRepository) { + this.peopleRepository = peopleRepository; + } + + @Override + public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { + Optional person = peopleRepository.findByUsername(s); + + if (person.isEmpty()) + throw new UsernameNotFoundException("User not found"); + + return new PersonDetails(person.get()); + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/RegistrationService.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/RegistrationService.java new file mode 100644 index 00000000..38cb0eec --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/RegistrationService.java @@ -0,0 +1,31 @@ +package ru.alishev.springcourse.FirstSecurityApp.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; +import ru.alishev.springcourse.FirstSecurityApp.repositories.PeopleRepository; + +/** + * @author Neil Alishev + */ +@Service +public class RegistrationService { + + private final PeopleRepository peopleRepository; + private final PasswordEncoder passwordEncoder; + + @Autowired + public RegistrationService(PeopleRepository peopleRepository, PasswordEncoder passwordEncoder) { + this.peopleRepository = peopleRepository; + this.passwordEncoder = passwordEncoder; + } + + @Transactional + public void register(Person person) { + person.setPassword(passwordEncoder.encode(person.getPassword())); + person.setRole("ROLE_USER"); + peopleRepository.save(person); + } +} diff --git a/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/util/PersonValidator.java b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/util/PersonValidator.java new file mode 100644 index 00000000..93694cc9 --- /dev/null +++ b/JWTApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/util/PersonValidator.java @@ -0,0 +1,41 @@ +package ru.alishev.springcourse.FirstSecurityApp.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; +import ru.alishev.springcourse.FirstSecurityApp.services.PersonDetailsService; + +/** + * @author Neil Alishev + */ +@Component +public class PersonValidator implements Validator { + + private final PersonDetailsService personDetailsService; + + @Autowired + public PersonValidator(PersonDetailsService personDetailsService) { + this.personDetailsService = personDetailsService; + } + + @Override + public boolean supports(Class aClass) { + return Person.class.equals(aClass); + } + + @Override + public void validate(Object o, Errors errors) { + Person person = (Person) o; + + try { + personDetailsService.loadUserByUsername(person.getUsername()); + } catch (UsernameNotFoundException ignored) { + return; // все ок, пользователь не найден + } + + errors.rejectValue("username", "", "Человек с таким именем пользователя уже существует"); + } +} diff --git a/JWTApp/src/main/resources/application.properties b/JWTApp/src/main/resources/application.properties new file mode 100644 index 00000000..97c20e5a --- /dev/null +++ b/JWTApp/src/main/resources/application.properties @@ -0,0 +1,9 @@ +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/security_app_db +spring.datasource.username=postgres +spring.datasource.password=postgres + +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.show_sql=true + +jwt_secret=SECRET \ No newline at end of file diff --git a/JWTApp/src/main/resources/templates/admin.html b/JWTApp/src/main/resources/templates/admin.html new file mode 100644 index 00000000..4e64e0a1 --- /dev/null +++ b/JWTApp/src/main/resources/templates/admin.html @@ -0,0 +1,10 @@ + + + + + Admin page + + +Admin page + + \ No newline at end of file diff --git a/JWTApp/src/main/resources/templates/auth/login.html b/JWTApp/src/main/resources/templates/auth/login.html new file mode 100644 index 00000000..f1cc287e --- /dev/null +++ b/JWTApp/src/main/resources/templates/auth/login.html @@ -0,0 +1,26 @@ + + + + + Login page + + + +
+ + + + +
+ + +
+ + +
+ Неправильные имя или пароль +
+
+ + + \ No newline at end of file diff --git a/JWTApp/src/main/resources/templates/auth/registration.html b/JWTApp/src/main/resources/templates/auth/registration.html new file mode 100644 index 00000000..990ab437 --- /dev/null +++ b/JWTApp/src/main/resources/templates/auth/registration.html @@ -0,0 +1,27 @@ + + + + + Registration + + + +
+ + +
Username Error
+
+ + +
Year of birth Error +
+
+ + +
Password Error
+
+ +
+ + + \ No newline at end of file diff --git a/JWTApp/src/main/resources/templates/hello.html b/JWTApp/src/main/resources/templates/hello.html new file mode 100644 index 00000000..b5f49686 --- /dev/null +++ b/JWTApp/src/main/resources/templates/hello.html @@ -0,0 +1,14 @@ + + + + + Hello + + +Hello world! +
+ +
+ + + \ No newline at end of file diff --git a/JWTApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityAppTests.java b/JWTApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityAppTests.java new file mode 100644 index 00000000..ffd4aff2 --- /dev/null +++ b/JWTApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/SpringSecurityAppTests.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.FirstSecurityApp; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringSecurityAppTests { + + @Test + void contextLoads() { + } + +} diff --git a/Lesson10.SpringAnnotations2/.gitignore b/Lesson10.SpringAnnotations2/.gitignore new file mode 100644 index 00000000..a5982c10 --- /dev/null +++ b/Lesson10.SpringAnnotations2/.gitignore @@ -0,0 +1,111 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar + diff --git a/Lesson10.SpringAnnotations2/pom.xml b/Lesson10.SpringAnnotations2/pom.xml new file mode 100644 index 00000000..dda9768b --- /dev/null +++ b/Lesson10.SpringAnnotations2/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + ru.alishev.springcourse + SpringAnnotations2 + 1.0-SNAPSHOT + war + + spring-ioc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + 5.1.4.RELEASE + + + + + org.springframework + spring-beans + 5.1.4.RELEASE + + + + + org.springframework + spring-context + 5.1.4.RELEASE + + + + + spring-ioc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/ClassicalMusic.java b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/ClassicalMusic.java new file mode 100644 index 00000000..daaf7968 --- /dev/null +++ b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/ClassicalMusic.java @@ -0,0 +1,14 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class ClassicalMusic implements Music { + @Override + public String getSong() { + return "Hungarian Rhapsody"; + } +} diff --git a/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/Computer.java b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/Computer.java new file mode 100644 index 00000000..c4c19ba6 --- /dev/null +++ b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/Computer.java @@ -0,0 +1,24 @@ +package ru.alishev.springcourse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class Computer { + private int id; + private MusicPlayer musicPlayer; + + @Autowired + public Computer(MusicPlayer musicPlayer) { + this.id = 1; + this.musicPlayer = musicPlayer; + } + + @Override + public String toString() { + return "Computer " + id + " " + musicPlayer.playMusic(); + } +} diff --git a/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/Music.java b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/Music.java new file mode 100644 index 00000000..3fe962a1 --- /dev/null +++ b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/Music.java @@ -0,0 +1,8 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public interface Music { + String getSong(); +} diff --git a/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/MusicPlayer.java b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/MusicPlayer.java new file mode 100644 index 00000000..2877ee80 --- /dev/null +++ b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/MusicPlayer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class MusicPlayer { + private ClassicalMusic classicalMusic; + private RockMusic rockMusic; + + @Autowired + public MusicPlayer(ClassicalMusic classicalMusic, RockMusic rockMusic) { + this.classicalMusic = classicalMusic; + this.rockMusic = rockMusic; + } + + public String playMusic() { + return "Playing: " + classicalMusic.getSong(); + } +} diff --git a/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/RockMusic.java b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/RockMusic.java new file mode 100644 index 00000000..5b5acc34 --- /dev/null +++ b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/RockMusic.java @@ -0,0 +1,14 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class RockMusic implements Music { + @Override + public String getSong() { + return "Wind cries Mary"; + } +} diff --git a/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/TestSpring.java b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/TestSpring.java new file mode 100644 index 00000000..1f170217 --- /dev/null +++ b/Lesson10.SpringAnnotations2/src/main/java/ru/alishev/springcourse/TestSpring.java @@ -0,0 +1,34 @@ +package ru.alishev.springcourse; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Neil Alishev + */ +public class TestSpring { + public static void main(String[] args) { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "applicationContext.xml" + ); + +// Music music = context.getBean("rockMusic", Music.class); +// +// MusicPlayer musicPlayer = new MusicPlayer(music); +// +// musicPlayer.playMusic(); +// +// Music music2 = context.getBean("classicalMusic", Music.class); +// +// MusicPlayer classicalMusicPlayer = new MusicPlayer(music2); +// +// classicalMusicPlayer.playMusic(); + +// MusicPlayer musicPlayer = context.getBean("musicPlayer", MusicPlayer.class); +// musicPlayer.playMusic(); + + Computer computer = context.getBean("computer", Computer.class); + System.out.println(computer); + + context.close(); + } +} diff --git a/Lesson10.SpringAnnotations2/src/main/resources/applicationContext.xml b/Lesson10.SpringAnnotations2/src/main/resources/applicationContext.xml new file mode 100644 index 00000000..6fcc7b1a --- /dev/null +++ b/Lesson10.SpringAnnotations2/src/main/resources/applicationContext.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/Lesson10.SpringAnnotations2/src/main/webapp/WEB-INF/web.xml b/Lesson10.SpringAnnotations2/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..9f88c1f9 --- /dev/null +++ b/Lesson10.SpringAnnotations2/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/Lesson10.SpringAnnotations2/src/main/webapp/index.jsp b/Lesson10.SpringAnnotations2/src/main/webapp/index.jsp new file mode 100644 index 00000000..c38169bb --- /dev/null +++ b/Lesson10.SpringAnnotations2/src/main/webapp/index.jsp @@ -0,0 +1,5 @@ + + +

Hello World!

+ + diff --git a/Lesson11.HWSolution/.gitignore b/Lesson11.HWSolution/.gitignore new file mode 100644 index 00000000..a5982c10 --- /dev/null +++ b/Lesson11.HWSolution/.gitignore @@ -0,0 +1,111 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar + diff --git a/Lesson11.HWSolution/pom.xml b/Lesson11.HWSolution/pom.xml new file mode 100644 index 00000000..dc5cd88d --- /dev/null +++ b/Lesson11.HWSolution/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + ru.alishev.springcourse + HWSolution + 1.0-SNAPSHOT + war + + spring-ioc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + 5.1.4.RELEASE + + + + + org.springframework + spring-beans + 5.1.4.RELEASE + + + + + org.springframework + spring-context + 5.1.4.RELEASE + + + + + spring-ioc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/ClassicalMusic.java b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/ClassicalMusic.java new file mode 100644 index 00000000..c0412b70 --- /dev/null +++ b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/ClassicalMusic.java @@ -0,0 +1,27 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class ClassicalMusic implements Music { + private List songs = new ArrayList<>(); + + // Блок инициализации объекта (англ. Instance initialization block) + // Выполняется каждый раз, когда создается объект класса + { + songs.add("Hungarian Rhapsody"); + songs.add("Symphony no. 5 in C Minor, op. 67"); + songs.add("Night on Bald Mountain"); + } + + @Override + public List getSongs() { + return songs; + } +} diff --git a/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/Music.java b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/Music.java new file mode 100644 index 00000000..67ccdd7c --- /dev/null +++ b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/Music.java @@ -0,0 +1,11 @@ +package ru.alishev.springcourse; + +import java.util.List; + +/** + * @author Neil Alishev + */ +public interface Music { + // Интерфейс тоже поменяли + List getSongs(); +} diff --git a/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/MusicGenre.java b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/MusicGenre.java new file mode 100644 index 00000000..92c1f521 --- /dev/null +++ b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/MusicGenre.java @@ -0,0 +1,8 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public enum MusicGenre { + CLASSICAL, ROCK +} diff --git a/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/MusicPlayer.java b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/MusicPlayer.java new file mode 100644 index 00000000..ec5794b2 --- /dev/null +++ b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/MusicPlayer.java @@ -0,0 +1,36 @@ +package ru.alishev.springcourse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Random; + +/** + * @author Neil Alishev + */ +@Component +public class MusicPlayer { + private ClassicalMusic classicalMusic; + private RockMusic rockMusic; + + @Autowired + public MusicPlayer(ClassicalMusic classicalMusic, RockMusic rockMusic) { + this.classicalMusic = classicalMusic; + this.rockMusic = rockMusic; + } + + public void playMusic(MusicGenre genre) { + Random random = new Random(); + + // случайное целое число между 0 и 2 + int randomNumber = random.nextInt(3); + + if (genre == MusicGenre.CLASSICAL) { + // случайная классическая песня + System.out.println(classicalMusic.getSongs().get(randomNumber)); + } else { + // случайная рок песня + System.out.println(rockMusic.getSongs().get(randomNumber)); + } + } +} diff --git a/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/RockMusic.java b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/RockMusic.java new file mode 100644 index 00000000..175ef301 --- /dev/null +++ b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/RockMusic.java @@ -0,0 +1,27 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class RockMusic implements Music { + private List songs = new ArrayList<>(); + + // Блок инициализации объекта (англ. Instance initialization block) + // Выполняется каждый раз, когда создается объект класса + { + songs.add("Wind cries Mary"); + songs.add("Paint it black"); + songs.add("Can't seem to make you mine"); + } + + @Override + public List getSongs() { + return songs; + } +} diff --git a/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/TestSpring.java b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/TestSpring.java new file mode 100644 index 00000000..d18fc534 --- /dev/null +++ b/Lesson11.HWSolution/src/main/java/ru/alishev/springcourse/TestSpring.java @@ -0,0 +1,21 @@ +package ru.alishev.springcourse; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Neil Alishev + */ +public class TestSpring { + public static void main(String[] args) { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "applicationContext.xml" + ); + + MusicPlayer musicPlayer = context.getBean("musicPlayer", MusicPlayer.class); + + musicPlayer.playMusic(MusicGenre.CLASSICAL); + musicPlayer.playMusic(MusicGenre.ROCK); + + context.close(); + } +} diff --git a/Lesson11.HWSolution/src/main/resources/applicationContext.xml b/Lesson11.HWSolution/src/main/resources/applicationContext.xml new file mode 100644 index 00000000..6fcc7b1a --- /dev/null +++ b/Lesson11.HWSolution/src/main/resources/applicationContext.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/Lesson11.HWSolution/src/main/webapp/WEB-INF/web.xml b/Lesson11.HWSolution/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..9f88c1f9 --- /dev/null +++ b/Lesson11.HWSolution/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/Lesson11.HWSolution/src/main/webapp/index.jsp b/Lesson11.HWSolution/src/main/webapp/index.jsp new file mode 100644 index 00000000..c38169bb --- /dev/null +++ b/Lesson11.HWSolution/src/main/webapp/index.jsp @@ -0,0 +1,5 @@ + + +

Hello World!

+ + diff --git a/Lesson11.SpringAnnotations3/.gitignore b/Lesson11.SpringAnnotations3/.gitignore new file mode 100644 index 00000000..a5982c10 --- /dev/null +++ b/Lesson11.SpringAnnotations3/.gitignore @@ -0,0 +1,111 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar + diff --git a/Lesson11.SpringAnnotations3/pom.xml b/Lesson11.SpringAnnotations3/pom.xml new file mode 100644 index 00000000..ae946141 --- /dev/null +++ b/Lesson11.SpringAnnotations3/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + ru.alishev.springcourse + SpringAnnotations3 + 1.0-SNAPSHOT + war + + spring-ioc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + 5.1.4.RELEASE + + + + + org.springframework + spring-beans + 5.1.4.RELEASE + + + + + org.springframework + spring-context + 5.1.4.RELEASE + + + + + spring-ioc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/ClassicalMusic.java b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/ClassicalMusic.java new file mode 100644 index 00000000..daaf7968 --- /dev/null +++ b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/ClassicalMusic.java @@ -0,0 +1,14 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class ClassicalMusic implements Music { + @Override + public String getSong() { + return "Hungarian Rhapsody"; + } +} diff --git a/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/Computer.java b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/Computer.java new file mode 100644 index 00000000..c4c19ba6 --- /dev/null +++ b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/Computer.java @@ -0,0 +1,24 @@ +package ru.alishev.springcourse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class Computer { + private int id; + private MusicPlayer musicPlayer; + + @Autowired + public Computer(MusicPlayer musicPlayer) { + this.id = 1; + this.musicPlayer = musicPlayer; + } + + @Override + public String toString() { + return "Computer " + id + " " + musicPlayer.playMusic(); + } +} diff --git a/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/Music.java b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/Music.java new file mode 100644 index 00000000..3fe962a1 --- /dev/null +++ b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/Music.java @@ -0,0 +1,8 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public interface Music { + String getSong(); +} diff --git a/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/MusicPlayer.java b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/MusicPlayer.java new file mode 100644 index 00000000..40c2f106 --- /dev/null +++ b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/MusicPlayer.java @@ -0,0 +1,25 @@ +package ru.alishev.springcourse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class MusicPlayer { + private Music music1; + private Music music2; + + @Autowired + public MusicPlayer(@Qualifier("rockMusic") Music music1, + @Qualifier("classicalMusic") Music music2) { + this.music1 = music1; + this.music2 = music2; + } + + public String playMusic() { + return "Playing: " + music1.getSong() + ", " + music2.getSong(); + } +} diff --git a/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/RockMusic.java b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/RockMusic.java new file mode 100644 index 00000000..5b5acc34 --- /dev/null +++ b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/RockMusic.java @@ -0,0 +1,14 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class RockMusic implements Music { + @Override + public String getSong() { + return "Wind cries Mary"; + } +} diff --git a/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/TestSpring.java b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/TestSpring.java new file mode 100644 index 00000000..1f170217 --- /dev/null +++ b/Lesson11.SpringAnnotations3/src/main/java/ru/alishev/springcourse/TestSpring.java @@ -0,0 +1,34 @@ +package ru.alishev.springcourse; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Neil Alishev + */ +public class TestSpring { + public static void main(String[] args) { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "applicationContext.xml" + ); + +// Music music = context.getBean("rockMusic", Music.class); +// +// MusicPlayer musicPlayer = new MusicPlayer(music); +// +// musicPlayer.playMusic(); +// +// Music music2 = context.getBean("classicalMusic", Music.class); +// +// MusicPlayer classicalMusicPlayer = new MusicPlayer(music2); +// +// classicalMusicPlayer.playMusic(); + +// MusicPlayer musicPlayer = context.getBean("musicPlayer", MusicPlayer.class); +// musicPlayer.playMusic(); + + Computer computer = context.getBean("computer", Computer.class); + System.out.println(computer); + + context.close(); + } +} diff --git a/Lesson11.SpringAnnotations3/src/main/resources/applicationContext.xml b/Lesson11.SpringAnnotations3/src/main/resources/applicationContext.xml new file mode 100644 index 00000000..6fcc7b1a --- /dev/null +++ b/Lesson11.SpringAnnotations3/src/main/resources/applicationContext.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/Lesson11.SpringAnnotations3/src/main/webapp/WEB-INF/web.xml b/Lesson11.SpringAnnotations3/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..9f88c1f9 --- /dev/null +++ b/Lesson11.SpringAnnotations3/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/Lesson11.SpringAnnotations3/src/main/webapp/index.jsp b/Lesson11.SpringAnnotations3/src/main/webapp/index.jsp new file mode 100644 index 00000000..c38169bb --- /dev/null +++ b/Lesson11.SpringAnnotations3/src/main/webapp/index.jsp @@ -0,0 +1,5 @@ + + +

Hello World!

+ + diff --git a/Lesson12.SpringAnnotations4/.gitignore b/Lesson12.SpringAnnotations4/.gitignore new file mode 100644 index 00000000..a5982c10 --- /dev/null +++ b/Lesson12.SpringAnnotations4/.gitignore @@ -0,0 +1,111 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar + diff --git a/Lesson12.SpringAnnotations4/pom.xml b/Lesson12.SpringAnnotations4/pom.xml new file mode 100644 index 00000000..05dc84fe --- /dev/null +++ b/Lesson12.SpringAnnotations4/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + ru.alishev.springcourse + SpringAnnotations4 + 1.0-SNAPSHOT + war + + spring-ioc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + 5.1.4.RELEASE + + + + + org.springframework + spring-beans + 5.1.4.RELEASE + + + + + org.springframework + spring-context + 5.1.4.RELEASE + + + + + spring-ioc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/ClassicalMusic.java b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/ClassicalMusic.java new file mode 100644 index 00000000..3343078d --- /dev/null +++ b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/ClassicalMusic.java @@ -0,0 +1,31 @@ +package ru.alishev.springcourse; + +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +/** + * @author Neil Alishev + */ +@Component +@Scope("prototype") +public class ClassicalMusic implements Music { + + @PostConstruct + public void doMyInit() { + System.out.println("Doing my initialization"); + } + + // Для Prototype бинов не вызывается destroy-метод! + @PreDestroy + public void doMyDestroy() { + System.out.println("Doing my destruction"); + } + + @Override + public String getSong() { + return "Hungarian Rhapsody"; + } +} diff --git a/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/Computer.java b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/Computer.java new file mode 100644 index 00000000..c4c19ba6 --- /dev/null +++ b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/Computer.java @@ -0,0 +1,24 @@ +package ru.alishev.springcourse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class Computer { + private int id; + private MusicPlayer musicPlayer; + + @Autowired + public Computer(MusicPlayer musicPlayer) { + this.id = 1; + this.musicPlayer = musicPlayer; + } + + @Override + public String toString() { + return "Computer " + id + " " + musicPlayer.playMusic(); + } +} diff --git a/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/Music.java b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/Music.java new file mode 100644 index 00000000..3fe962a1 --- /dev/null +++ b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/Music.java @@ -0,0 +1,8 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public interface Music { + String getSong(); +} diff --git a/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/MusicPlayer.java b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/MusicPlayer.java new file mode 100644 index 00000000..d163907b --- /dev/null +++ b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/MusicPlayer.java @@ -0,0 +1,41 @@ +package ru.alishev.springcourse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class MusicPlayer { + + @Value("${musicPlayer.name}") + private String name; + + @Value("${musicPlayer.volume}") + private int volume; + + public String getName() { + return name; + } + + public int getVolume() { + return volume; + } + + private Music music1; + private Music music2; + + @Autowired + public MusicPlayer(@Qualifier("rockMusic") Music music1, + @Qualifier("classicalMusic") Music music2) { + this.music1 = music1; + this.music2 = music2; + } + + public String playMusic() { + return "Playing: " + music1.getSong() + ", " + music2.getSong(); + } +} diff --git a/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/RockMusic.java b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/RockMusic.java new file mode 100644 index 00000000..5b5acc34 --- /dev/null +++ b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/RockMusic.java @@ -0,0 +1,14 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class RockMusic implements Music { + @Override + public String getSong() { + return "Wind cries Mary"; + } +} diff --git a/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/TestSpring.java b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/TestSpring.java new file mode 100644 index 00000000..8f445b76 --- /dev/null +++ b/Lesson12.SpringAnnotations4/src/main/java/ru/alishev/springcourse/TestSpring.java @@ -0,0 +1,26 @@ +package ru.alishev.springcourse; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Neil Alishev + */ +public class TestSpring { + public static void main(String[] args) { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "applicationContext.xml" + ); + + MusicPlayer musicPlayer = context.getBean("musicPlayer", MusicPlayer.class); + + System.out.println(musicPlayer.getName()); + System.out.println(musicPlayer.getVolume()); + + ClassicalMusic classicalMusic1 = context.getBean("classicalMusic", ClassicalMusic.class); + ClassicalMusic classicalMusic2 = context.getBean("classicalMusic", ClassicalMusic.class); + + System.out.println(classicalMusic1 == classicalMusic2); + + context.close(); + } +} diff --git a/Lesson12.SpringAnnotations4/src/main/resources/applicationContext.xml b/Lesson12.SpringAnnotations4/src/main/resources/applicationContext.xml new file mode 100644 index 00000000..f2b73a6a --- /dev/null +++ b/Lesson12.SpringAnnotations4/src/main/resources/applicationContext.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/Lesson12.SpringAnnotations4/src/main/resources/musicPlayer.properties b/Lesson12.SpringAnnotations4/src/main/resources/musicPlayer.properties new file mode 100644 index 00000000..fb2c337e --- /dev/null +++ b/Lesson12.SpringAnnotations4/src/main/resources/musicPlayer.properties @@ -0,0 +1,2 @@ +musicPlayer.name=Some name +musicPlayer.volume=60 \ No newline at end of file diff --git a/Lesson12.SpringAnnotations4/src/main/webapp/WEB-INF/web.xml b/Lesson12.SpringAnnotations4/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..9f88c1f9 --- /dev/null +++ b/Lesson12.SpringAnnotations4/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/Lesson12.SpringAnnotations4/src/main/webapp/index.jsp b/Lesson12.SpringAnnotations4/src/main/webapp/index.jsp new file mode 100644 index 00000000..c38169bb --- /dev/null +++ b/Lesson12.SpringAnnotations4/src/main/webapp/index.jsp @@ -0,0 +1,5 @@ + + +

Hello World!

+ + diff --git a/Lesson13.HWSolution/.gitignore b/Lesson13.HWSolution/.gitignore new file mode 100644 index 00000000..a5982c10 --- /dev/null +++ b/Lesson13.HWSolution/.gitignore @@ -0,0 +1,111 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar + diff --git a/Lesson13.HWSolution/pom.xml b/Lesson13.HWSolution/pom.xml new file mode 100644 index 00000000..dc5cd88d --- /dev/null +++ b/Lesson13.HWSolution/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + ru.alishev.springcourse + HWSolution + 1.0-SNAPSHOT + war + + spring-ioc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + 5.1.4.RELEASE + + + + + org.springframework + spring-beans + 5.1.4.RELEASE + + + + + org.springframework + spring-context + 5.1.4.RELEASE + + + + + spring-ioc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/Computer.java b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/Computer.java new file mode 100644 index 00000000..d1c24a72 --- /dev/null +++ b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/Computer.java @@ -0,0 +1,19 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public class Computer { + private int id; + private MusicPlayer musicPlayer; + + public Computer(MusicPlayer musicPlayer) { + this.id = 1; + this.musicPlayer = musicPlayer; + } + + @Override + public String toString() { + return "Computer " + id + " " + musicPlayer.playMusic(); + } +} diff --git a/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/Music.java b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/Music.java new file mode 100644 index 00000000..3fe962a1 --- /dev/null +++ b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/Music.java @@ -0,0 +1,8 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public interface Music { + String getSong(); +} diff --git a/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/MusicPlayer.java b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/MusicPlayer.java new file mode 100644 index 00000000..264329bb --- /dev/null +++ b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/MusicPlayer.java @@ -0,0 +1,39 @@ +package ru.alishev.springcourse; + +import org.springframework.beans.factory.annotation.Value; + +import java.util.List; +import java.util.Random; + +/** + * @author Neil Alishev + */ +public class MusicPlayer { + + @Value("${musicPlayer.name}") + private String name; + + @Value("${musicPlayer.volume}") + private int volume; + + private List musicList; + + public MusicPlayer(List musicList) { + this.musicList = musicList; + } + + public String getName() { + return name; + } + + public int getVolume() { + return volume; + } + + public String playMusic() { + Random random = new Random(); + + return "Playing: " + musicList.get(random.nextInt(musicList.size())).getSong() + + " with volume " + this.volume; + } +} diff --git a/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/TestSpring.java b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/TestSpring.java new file mode 100644 index 00000000..f76c313d --- /dev/null +++ b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/TestSpring.java @@ -0,0 +1,21 @@ +package ru.alishev.springcourse; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import ru.alishev.springcourse.config.SpringConfig; + +/** + * @author Neil Alishev + */ +public class TestSpring { + public static void main(String[] args) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + SpringConfig.class + ); + + MusicPlayer musicPlayer = context.getBean("musicPlayer", MusicPlayer.class); + + System.out.println(musicPlayer.playMusic()); + + context.close(); + } +} diff --git a/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..67def457 --- /dev/null +++ b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,54 @@ +package ru.alishev.springcourse.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.annotation.Scope; +import ru.alishev.springcourse.Computer; +import ru.alishev.springcourse.Music; +import ru.alishev.springcourse.MusicPlayer; +import ru.alishev.springcourse.genres.ClassicalMusic; +import ru.alishev.springcourse.genres.JazzMusic; +import ru.alishev.springcourse.genres.RockMusic; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Configuration +@PropertySource("classpath:musicPlayer.properties") +public class SpringConfig { + @Bean + @Scope("prototype") + public ClassicalMusic classicalMusic() { + return new ClassicalMusic(); + } + + @Bean + public RockMusic rockMusic() { + return new RockMusic(); + } + + @Bean + public JazzMusic jazzMusic() { + return new JazzMusic(); + } + + @Bean + public List musicList() { + // Этот лист неизменяемый (immutable) + return Arrays.asList(classicalMusic(), rockMusic(), jazzMusic()); + } + + @Bean + public MusicPlayer musicPlayer() { + return new MusicPlayer(musicList()); + } + + @Bean + public Computer computer() { + return new Computer(musicPlayer()); + } +} \ No newline at end of file diff --git a/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/genres/ClassicalMusic.java b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/genres/ClassicalMusic.java new file mode 100644 index 00000000..a3825806 --- /dev/null +++ b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/genres/ClassicalMusic.java @@ -0,0 +1,28 @@ +package ru.alishev.springcourse.genres; + +import ru.alishev.springcourse.Music; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +/** + * @author Neil Alishev + */ +public class ClassicalMusic implements Music { + + @PostConstruct + public void doMyInit() { + System.out.println("Doing my initialization"); + } + + // Для Prototype бинов не вызывается destroy-метод! + @PreDestroy + public void doMyDestroy() { + System.out.println("Doing my destruction"); + } + + @Override + public String getSong() { + return "Hungarian Rhapsody"; + } +} diff --git a/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/genres/JazzMusic.java b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/genres/JazzMusic.java new file mode 100644 index 00000000..661c360c --- /dev/null +++ b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/genres/JazzMusic.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.genres; + +import ru.alishev.springcourse.Music; + +/** + * @author Neil Alishev + */ +public class JazzMusic implements Music { + @Override + public String getSong() { + return "Take five"; + } +} diff --git a/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/genres/RockMusic.java b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/genres/RockMusic.java new file mode 100644 index 00000000..3df8a599 --- /dev/null +++ b/Lesson13.HWSolution/src/main/java/ru/alishev/springcourse/genres/RockMusic.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.genres; + +import ru.alishev.springcourse.Music; + +/** + * @author Neil Alishev + */ +public class RockMusic implements Music { + @Override + public String getSong() { + return "Wind cries Mary"; + } +} diff --git a/Lesson13.HWSolution/src/main/resources/musicPlayer.properties b/Lesson13.HWSolution/src/main/resources/musicPlayer.properties new file mode 100644 index 00000000..fb2c337e --- /dev/null +++ b/Lesson13.HWSolution/src/main/resources/musicPlayer.properties @@ -0,0 +1,2 @@ +musicPlayer.name=Some name +musicPlayer.volume=60 \ No newline at end of file diff --git a/Lesson13.HWSolution/src/main/webapp/WEB-INF/web.xml b/Lesson13.HWSolution/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..9f88c1f9 --- /dev/null +++ b/Lesson13.HWSolution/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/Lesson13.HWSolution/src/main/webapp/index.jsp b/Lesson13.HWSolution/src/main/webapp/index.jsp new file mode 100644 index 00000000..c38169bb --- /dev/null +++ b/Lesson13.HWSolution/src/main/webapp/index.jsp @@ -0,0 +1,5 @@ + + +

Hello World!

+ + diff --git a/Lesson13.SpringJavaConfiguration/.gitignore b/Lesson13.SpringJavaConfiguration/.gitignore new file mode 100644 index 00000000..a5982c10 --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/.gitignore @@ -0,0 +1,111 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar + diff --git a/Lesson13.SpringJavaConfiguration/pom.xml b/Lesson13.SpringJavaConfiguration/pom.xml new file mode 100644 index 00000000..1dfcb7ad --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + ru.alishev.springcourse + SpringJavaConfiguration + 1.0-SNAPSHOT + war + + spring-ioc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + 5.1.4.RELEASE + + + + + org.springframework + spring-beans + 5.1.4.RELEASE + + + + + org.springframework + spring-context + 5.1.4.RELEASE + + + + + spring-ioc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/ClassicalMusic.java b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/ClassicalMusic.java new file mode 100644 index 00000000..f0b5f9d6 --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/ClassicalMusic.java @@ -0,0 +1,26 @@ +package ru.alishev.springcourse; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +/** + * @author Neil Alishev + */ +public class ClassicalMusic implements Music { + + @PostConstruct + public void doMyInit() { + System.out.println("Doing my initialization"); + } + + // Для Prototype бинов не вызывается destroy-метод! + @PreDestroy + public void doMyDestroy() { + System.out.println("Doing my destruction"); + } + + @Override + public String getSong() { + return "Hungarian Rhapsody"; + } +} diff --git a/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/Computer.java b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/Computer.java new file mode 100644 index 00000000..d1c24a72 --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/Computer.java @@ -0,0 +1,19 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public class Computer { + private int id; + private MusicPlayer musicPlayer; + + public Computer(MusicPlayer musicPlayer) { + this.id = 1; + this.musicPlayer = musicPlayer; + } + + @Override + public String toString() { + return "Computer " + id + " " + musicPlayer.playMusic(); + } +} diff --git a/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/Music.java b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/Music.java new file mode 100644 index 00000000..3fe962a1 --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/Music.java @@ -0,0 +1,8 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public interface Music { + String getSong(); +} diff --git a/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/MusicPlayer.java b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/MusicPlayer.java new file mode 100644 index 00000000..62a26102 --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/MusicPlayer.java @@ -0,0 +1,37 @@ +package ru.alishev.springcourse; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; + +/** + * @author Neil Alishev + */ +public class MusicPlayer { + + @Value("${musicPlayer.name}") + private String name; + + @Value("${musicPlayer.volume}") + private int volume; + + public String getName() { + return name; + } + + public int getVolume() { + return volume; + } + + private Music music1; + private Music music2; + + public MusicPlayer(@Qualifier("rockMusic") Music music1, + @Qualifier("classicalMusic") Music music2) { + this.music1 = music1; + this.music2 = music2; + } + + public String playMusic() { + return "Playing: " + music1.getSong() + ", " + music2.getSong(); + } +} diff --git a/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/RockMusic.java b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/RockMusic.java new file mode 100644 index 00000000..cccc5700 --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/RockMusic.java @@ -0,0 +1,11 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public class RockMusic implements Music { + @Override + public String getSong() { + return "Wind cries Mary"; + } +} diff --git a/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/SpringConfig.java b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/SpringConfig.java new file mode 100644 index 00000000..cec85b3b --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/SpringConfig.java @@ -0,0 +1,32 @@ +package ru.alishev.springcourse; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +/** + * @author Neil Alishev + */ +@Configuration +@PropertySource("classpath:musicPlayer.properties") +public class SpringConfig { + @Bean + public ClassicalMusic classicalMusic() { + return new ClassicalMusic(); + } + + @Bean + public RockMusic rockMusic() { + return new RockMusic(); + } + + @Bean + public MusicPlayer musicPlayer() { + return new MusicPlayer(rockMusic(), classicalMusic()); + } + + @Bean + public Computer computer() { + return new Computer(musicPlayer()); + } +} diff --git a/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/TestSpring.java b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/TestSpring.java new file mode 100644 index 00000000..ed698e1f --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/src/main/java/ru/alishev/springcourse/TestSpring.java @@ -0,0 +1,26 @@ +package ru.alishev.springcourse; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * @author Neil Alishev + */ +public class TestSpring { + public static void main(String[] args) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + SpringConfig.class + ); + + MusicPlayer musicPlayer = context.getBean("musicPlayer", MusicPlayer.class); + + System.out.println(musicPlayer.getName()); + System.out.println(musicPlayer.getVolume()); + + ClassicalMusic classicalMusic1 = context.getBean("classicalMusic", ClassicalMusic.class); + ClassicalMusic classicalMusic2 = context.getBean("classicalMusic", ClassicalMusic.class); + + System.out.println(classicalMusic1 == classicalMusic2); + + context.close(); + } +} diff --git a/Lesson13.SpringJavaConfiguration/src/main/resources/musicPlayer.properties b/Lesson13.SpringJavaConfiguration/src/main/resources/musicPlayer.properties new file mode 100644 index 00000000..fb2c337e --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/src/main/resources/musicPlayer.properties @@ -0,0 +1,2 @@ +musicPlayer.name=Some name +musicPlayer.volume=60 \ No newline at end of file diff --git a/Lesson13.SpringJavaConfiguration/src/main/webapp/WEB-INF/web.xml b/Lesson13.SpringJavaConfiguration/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..9f88c1f9 --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/Lesson13.SpringJavaConfiguration/src/main/webapp/index.jsp b/Lesson13.SpringJavaConfiguration/src/main/webapp/index.jsp new file mode 100644 index 00000000..c38169bb --- /dev/null +++ b/Lesson13.SpringJavaConfiguration/src/main/webapp/index.jsp @@ -0,0 +1,5 @@ + + +

Hello World!

+ + diff --git a/Lesson15.SpringMVCApp1/pom.xml b/Lesson15.SpringMVCApp1/pom.xml new file mode 100644 index 00000000..cdada9fd --- /dev/null +++ b/Lesson15.SpringMVCApp1/pom.xml @@ -0,0 +1,99 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-mvc-app1 + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson15.SpringMVCApp1/src/main/java/ru/alishev/springcourse/HelloController.java b/Lesson15.SpringMVCApp1/src/main/java/ru/alishev/springcourse/HelloController.java new file mode 100644 index 00000000..4a1d231d --- /dev/null +++ b/Lesson15.SpringMVCApp1/src/main/java/ru/alishev/springcourse/HelloController.java @@ -0,0 +1,16 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * @author Neil Alishev + */ +@Controller +public class HelloController { + + @GetMapping("/hello-world") + public String sayHello() { + return "hello_world"; + } +} diff --git a/Lesson15.SpringMVCApp1/src/main/webapp/WEB-INF/applicationContextMVC.xml b/Lesson15.SpringMVCApp1/src/main/webapp/WEB-INF/applicationContextMVC.xml new file mode 100644 index 00000000..221ae146 --- /dev/null +++ b/Lesson15.SpringMVCApp1/src/main/webapp/WEB-INF/applicationContextMVC.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Lesson15.SpringMVCApp1/src/main/webapp/WEB-INF/views/hello_world.html b/Lesson15.SpringMVCApp1/src/main/webapp/WEB-INF/views/hello_world.html new file mode 100644 index 00000000..9d47ab54 --- /dev/null +++ b/Lesson15.SpringMVCApp1/src/main/webapp/WEB-INF/views/hello_world.html @@ -0,0 +1,15 @@ + + + + + + My app + + + + +

Hello world!

+ + + + \ No newline at end of file diff --git a/Lesson15.SpringMVCApp1/src/main/webapp/WEB-INF/web.xml b/Lesson15.SpringMVCApp1/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..182d596e --- /dev/null +++ b/Lesson15.SpringMVCApp1/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,26 @@ + + + + spring-mvc-app1 + + + + + dispatcher + org.springframework.web.servlet.DispatcherServlet + + contextConfigLocation + /WEB-INF/applicationContextMVC.xml + + 1 + + + + dispatcher + / + + + \ No newline at end of file diff --git a/Lesson16.SpringMVCAppJavaConfig/pom.xml b/Lesson16.SpringMVCAppJavaConfig/pom.xml new file mode 100644 index 00000000..6058d3e8 --- /dev/null +++ b/Lesson16.SpringMVCAppJavaConfig/pom.xml @@ -0,0 +1,106 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-mvc-app-java-config + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson16.SpringMVCAppJavaConfig/src/main/java/ru/alishev/springcourse/HelloController.java b/Lesson16.SpringMVCAppJavaConfig/src/main/java/ru/alishev/springcourse/HelloController.java new file mode 100644 index 00000000..f19a5b8f --- /dev/null +++ b/Lesson16.SpringMVCAppJavaConfig/src/main/java/ru/alishev/springcourse/HelloController.java @@ -0,0 +1,15 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * @author Neil Alishev + */ +@Controller +public class HelloController { + @GetMapping("/hello-world") + public String sayHello() { + return "hello_world"; + } +} diff --git a/Lesson16.SpringMVCAppJavaConfig/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson16.SpringMVCAppJavaConfig/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson16.SpringMVCAppJavaConfig/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson16.SpringMVCAppJavaConfig/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson16.SpringMVCAppJavaConfig/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson16.SpringMVCAppJavaConfig/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson16.SpringMVCAppJavaConfig/src/main/webapp/WEB-INF/views/hello_world.html b/Lesson16.SpringMVCAppJavaConfig/src/main/webapp/WEB-INF/views/hello_world.html new file mode 100644 index 00000000..9d47ab54 --- /dev/null +++ b/Lesson16.SpringMVCAppJavaConfig/src/main/webapp/WEB-INF/views/hello_world.html @@ -0,0 +1,15 @@ + + + + + + My app + + + + +

Hello world!

+ + + + \ No newline at end of file diff --git a/Lesson17.SpringControllersIntro/pom.xml b/Lesson17.SpringControllersIntro/pom.xml new file mode 100644 index 00000000..d7d0363a --- /dev/null +++ b/Lesson17.SpringControllersIntro/pom.xml @@ -0,0 +1,106 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-controllers-intro + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/controllers/FirstController.java b/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/controllers/FirstController.java new file mode 100644 index 00000000..2d4a9e87 --- /dev/null +++ b/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/controllers/FirstController.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/first") +public class FirstController { + + @GetMapping("/hello") + public String helloPage() { + return "first/hello"; + } + + @GetMapping("/goodbye") + public String goodByePage() { + return "first/goodbye"; + } +} diff --git a/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/controllers/SecondController.java b/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/controllers/SecondController.java new file mode 100644 index 00000000..0700c805 --- /dev/null +++ b/Lesson17.SpringControllersIntro/src/main/java/ru/alishev/springcourse/controllers/SecondController.java @@ -0,0 +1,16 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * @author Neil Alishev + */ +@Controller +public class SecondController { + + @GetMapping("/exit") + public String exit() { + return "second/exit"; + } +} diff --git a/Lesson17.SpringControllersIntro/src/main/webapp/WEB-INF/views/first/goodbye.html b/Lesson17.SpringControllersIntro/src/main/webapp/WEB-INF/views/first/goodbye.html new file mode 100644 index 00000000..1d1cd3ca --- /dev/null +++ b/Lesson17.SpringControllersIntro/src/main/webapp/WEB-INF/views/first/goodbye.html @@ -0,0 +1,12 @@ + + + + + Goodbye + + +Goodbye! + +Say hello or Exit + + \ No newline at end of file diff --git a/Lesson17.SpringControllersIntro/src/main/webapp/WEB-INF/views/first/hello.html b/Lesson17.SpringControllersIntro/src/main/webapp/WEB-INF/views/first/hello.html new file mode 100644 index 00000000..ee20cf13 --- /dev/null +++ b/Lesson17.SpringControllersIntro/src/main/webapp/WEB-INF/views/first/hello.html @@ -0,0 +1,12 @@ + + + + + Hello + + +Hello! + +Say goodbye or Exit + + \ No newline at end of file diff --git a/Lesson17.SpringControllersIntro/src/main/webapp/WEB-INF/views/second/exit.html b/Lesson17.SpringControllersIntro/src/main/webapp/WEB-INF/views/second/exit.html new file mode 100644 index 00000000..27f349bf --- /dev/null +++ b/Lesson17.SpringControllersIntro/src/main/webapp/WEB-INF/views/second/exit.html @@ -0,0 +1,10 @@ + + + + + Exit + + +No more links + + \ No newline at end of file diff --git a/Lesson17_Starter.SpringControllersIntro/pom.xml b/Lesson17_Starter.SpringControllersIntro/pom.xml new file mode 100644 index 00000000..d7d0363a --- /dev/null +++ b/Lesson17_Starter.SpringControllersIntro/pom.xml @@ -0,0 +1,106 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-controllers-intro + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson17_Starter.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson17_Starter.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson17_Starter.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson17_Starter.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson17_Starter.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson17_Starter.SpringControllersIntro/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson19.SpringRequestParameters/pom.xml b/Lesson19.SpringRequestParameters/pom.xml new file mode 100644 index 00000000..442482aa --- /dev/null +++ b/Lesson19.SpringRequestParameters/pom.xml @@ -0,0 +1,106 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-request-parameters + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/FirstController.java b/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/FirstController.java new file mode 100644 index 00000000..3565b66e --- /dev/null +++ b/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/FirstController.java @@ -0,0 +1,28 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/first") +public class FirstController { + + @GetMapping("/hello") + public String helloPage(@RequestParam(value = "name", required = false) String name, + @RequestParam(value = "surname", required = false) String surname) { + + System.out.println("Hello, " + name + " " + surname); + + return "first/hello"; + } + + @GetMapping("/goodbye") + public String goodByePage() { + return "first/goodbye"; + } +} diff --git a/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/SecondController.java b/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/SecondController.java new file mode 100644 index 00000000..0700c805 --- /dev/null +++ b/Lesson19.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/SecondController.java @@ -0,0 +1,16 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * @author Neil Alishev + */ +@Controller +public class SecondController { + + @GetMapping("/exit") + public String exit() { + return "second/exit"; + } +} diff --git a/Lesson19.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/goodbye.html b/Lesson19.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/goodbye.html new file mode 100644 index 00000000..1d1cd3ca --- /dev/null +++ b/Lesson19.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/goodbye.html @@ -0,0 +1,12 @@ + + + + + Goodbye + + +Goodbye! + +Say hello or Exit + + \ No newline at end of file diff --git a/Lesson19.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/hello.html b/Lesson19.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/hello.html new file mode 100644 index 00000000..958fe48d --- /dev/null +++ b/Lesson19.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/hello.html @@ -0,0 +1,13 @@ + + + + + Hello + + +Hello! + +Say goodbye or Exit +or Request with parameters + + \ No newline at end of file diff --git a/Lesson19.SpringRequestParameters/src/main/webapp/WEB-INF/views/second/exit.html b/Lesson19.SpringRequestParameters/src/main/webapp/WEB-INF/views/second/exit.html new file mode 100644 index 00000000..27f349bf --- /dev/null +++ b/Lesson19.SpringRequestParameters/src/main/webapp/WEB-INF/views/second/exit.html @@ -0,0 +1,10 @@ + + + + + Exit + + +No more links + + \ No newline at end of file diff --git a/Lesson19_Starter.SpringRequestParameters/pom.xml b/Lesson19_Starter.SpringRequestParameters/pom.xml new file mode 100644 index 00000000..442482aa --- /dev/null +++ b/Lesson19_Starter.SpringRequestParameters/pom.xml @@ -0,0 +1,106 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-request-parameters + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/FirstController.java b/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/FirstController.java new file mode 100644 index 00000000..2d4a9e87 --- /dev/null +++ b/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/FirstController.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/first") +public class FirstController { + + @GetMapping("/hello") + public String helloPage() { + return "first/hello"; + } + + @GetMapping("/goodbye") + public String goodByePage() { + return "first/goodbye"; + } +} diff --git a/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/SecondController.java b/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/SecondController.java new file mode 100644 index 00000000..0700c805 --- /dev/null +++ b/Lesson19_Starter.SpringRequestParameters/src/main/java/ru/alishev/springcourse/controllers/SecondController.java @@ -0,0 +1,16 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * @author Neil Alishev + */ +@Controller +public class SecondController { + + @GetMapping("/exit") + public String exit() { + return "second/exit"; + } +} diff --git a/Lesson19_Starter.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/goodbye.html b/Lesson19_Starter.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/goodbye.html new file mode 100644 index 00000000..1d1cd3ca --- /dev/null +++ b/Lesson19_Starter.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/goodbye.html @@ -0,0 +1,12 @@ + + + + + Goodbye + + +Goodbye! + +Say hello or Exit + + \ No newline at end of file diff --git a/Lesson19_Starter.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/hello.html b/Lesson19_Starter.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/hello.html new file mode 100644 index 00000000..ee20cf13 --- /dev/null +++ b/Lesson19_Starter.SpringRequestParameters/src/main/webapp/WEB-INF/views/first/hello.html @@ -0,0 +1,12 @@ + + + + + Hello + + +Hello! + +Say goodbye or Exit + + \ No newline at end of file diff --git a/Lesson19_Starter.SpringRequestParameters/src/main/webapp/WEB-INF/views/second/exit.html b/Lesson19_Starter.SpringRequestParameters/src/main/webapp/WEB-INF/views/second/exit.html new file mode 100644 index 00000000..27f349bf --- /dev/null +++ b/Lesson19_Starter.SpringRequestParameters/src/main/webapp/WEB-INF/views/second/exit.html @@ -0,0 +1,10 @@ + + + + + Exit + + +No more links + + \ No newline at end of file diff --git a/Lesson20.IntroToModel/pom.xml b/Lesson20.IntroToModel/pom.xml new file mode 100644 index 00000000..c1ba0a6c --- /dev/null +++ b/Lesson20.IntroToModel/pom.xml @@ -0,0 +1,106 @@ + + + + 4.0.0 + + ru.alishev.springcourse + intro-to-model + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..dd640487 --- /dev/null +++ b/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,55 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + templateResolver.setCharacterEncoding("UTF-8"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + resolver.setCharacterEncoding("UTF-8"); + registry.viewResolver(resolver); + } +} diff --git a/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/FirstController.java b/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/FirstController.java new file mode 100644 index 00000000..055af5eb --- /dev/null +++ b/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/FirstController.java @@ -0,0 +1,60 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/first") +public class FirstController { + + @GetMapping("/hello") + public String helloPage(@RequestParam(value = "name", required = false) String name, + @RequestParam(value = "surname", required = false) String surname, + Model model) { + + // System.out.println("Hello, " + name + " " + surname); + model.addAttribute("message", "Hello, " + name + " " + surname); + + return "first/hello"; + } + + @GetMapping("/goodbye") + public String goodByePage() { + return "first/goodbye"; + } + + @GetMapping("/calculator") + public String calculator(@RequestParam("a") int a, @RequestParam("b") int b, + @RequestParam("action") String action, Model model) { + + double result; + + switch (action) { + case "multiplication": + result = a * b; + break; + case "division": + result = a / (double) b; + break; + case "subtraction": + result = a - b; + break; + case "addition": + result = a + b; + break; + default: + result = 0; + break; + } + + model.addAttribute("result", result); + + return "first/calculator"; + } +} diff --git a/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/SecondController.java b/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/SecondController.java new file mode 100644 index 00000000..0700c805 --- /dev/null +++ b/Lesson20.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/SecondController.java @@ -0,0 +1,16 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * @author Neil Alishev + */ +@Controller +public class SecondController { + + @GetMapping("/exit") + public String exit() { + return "second/exit"; + } +} diff --git a/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/first/calculator.html b/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/first/calculator.html new file mode 100644 index 00000000..59a84a4e --- /dev/null +++ b/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/first/calculator.html @@ -0,0 +1,10 @@ + + + + + Calculator + + +Результат:

+ + \ No newline at end of file diff --git a/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/first/goodbye.html b/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/first/goodbye.html new file mode 100644 index 00000000..1d1cd3ca --- /dev/null +++ b/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/first/goodbye.html @@ -0,0 +1,12 @@ + + + + + Goodbye + + +Goodbye! + +Say hello or Exit + + \ No newline at end of file diff --git a/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/first/hello.html b/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/first/hello.html new file mode 100644 index 00000000..ac5decdb --- /dev/null +++ b/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/first/hello.html @@ -0,0 +1,16 @@ + + + + + Hello + + +Hello! + +Say goodbye or Exit +or Request with parameters + +

+ + + \ No newline at end of file diff --git a/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/second/exit.html b/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/second/exit.html new file mode 100644 index 00000000..27f349bf --- /dev/null +++ b/Lesson20.IntroToModel/src/main/webapp/WEB-INF/views/second/exit.html @@ -0,0 +1,10 @@ + + + + + Exit + + +No more links + + \ No newline at end of file diff --git a/Lesson20_Starter.IntroToModel/pom.xml b/Lesson20_Starter.IntroToModel/pom.xml new file mode 100644 index 00000000..c1ba0a6c --- /dev/null +++ b/Lesson20_Starter.IntroToModel/pom.xml @@ -0,0 +1,106 @@ + + + + 4.0.0 + + ru.alishev.springcourse + intro-to-model + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/FirstController.java b/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/FirstController.java new file mode 100644 index 00000000..3565b66e --- /dev/null +++ b/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/FirstController.java @@ -0,0 +1,28 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/first") +public class FirstController { + + @GetMapping("/hello") + public String helloPage(@RequestParam(value = "name", required = false) String name, + @RequestParam(value = "surname", required = false) String surname) { + + System.out.println("Hello, " + name + " " + surname); + + return "first/hello"; + } + + @GetMapping("/goodbye") + public String goodByePage() { + return "first/goodbye"; + } +} diff --git a/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/SecondController.java b/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/SecondController.java new file mode 100644 index 00000000..0700c805 --- /dev/null +++ b/Lesson20_Starter.IntroToModel/src/main/java/ru/alishev/springcourse/controllers/SecondController.java @@ -0,0 +1,16 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * @author Neil Alishev + */ +@Controller +public class SecondController { + + @GetMapping("/exit") + public String exit() { + return "second/exit"; + } +} diff --git a/Lesson20_Starter.IntroToModel/src/main/webapp/WEB-INF/views/first/goodbye.html b/Lesson20_Starter.IntroToModel/src/main/webapp/WEB-INF/views/first/goodbye.html new file mode 100644 index 00000000..1d1cd3ca --- /dev/null +++ b/Lesson20_Starter.IntroToModel/src/main/webapp/WEB-INF/views/first/goodbye.html @@ -0,0 +1,12 @@ + + + + + Goodbye + + +Goodbye! + +Say hello or Exit + + \ No newline at end of file diff --git a/Lesson20_Starter.IntroToModel/src/main/webapp/WEB-INF/views/first/hello.html b/Lesson20_Starter.IntroToModel/src/main/webapp/WEB-INF/views/first/hello.html new file mode 100644 index 00000000..958fe48d --- /dev/null +++ b/Lesson20_Starter.IntroToModel/src/main/webapp/WEB-INF/views/first/hello.html @@ -0,0 +1,13 @@ + + + + + Hello + + +Hello! + +Say goodbye or Exit +or Request with parameters + + \ No newline at end of file diff --git a/Lesson20_Starter.IntroToModel/src/main/webapp/WEB-INF/views/second/exit.html b/Lesson20_Starter.IntroToModel/src/main/webapp/WEB-INF/views/second/exit.html new file mode 100644 index 00000000..27f349bf --- /dev/null +++ b/Lesson20_Starter.IntroToModel/src/main/webapp/WEB-INF/views/second/exit.html @@ -0,0 +1,10 @@ + + + + + Exit + + +No more links + + \ No newline at end of file diff --git a/Lesson21.CRUD_App1/pom.xml b/Lesson21.CRUD_App1/pom.xml new file mode 100644 index 00000000..ad5b303f --- /dev/null +++ b/Lesson21.CRUD_App1/pom.xml @@ -0,0 +1,116 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-crud-app1 + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..80146ec6 --- /dev/null +++ b/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,36 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import ru.alishev.springcourse.dao.PersonDAO; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } +} diff --git a/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..04a711cc --- /dev/null +++ b/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,33 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + private List people; + + { + people = new ArrayList<>(); + + people.add(new Person(++PEOPLE_COUNT, "Tom")); + people.add(new Person(++PEOPLE_COUNT, "Bob")); + people.add(new Person(++PEOPLE_COUNT, "Mike")); + people.add(new Person(++PEOPLE_COUNT, "Katy")); + } + + public List index() { + return people; + } + + public Person show(int id) { + return people.stream().filter(person -> person.getId() == id).findAny().orElse(null); + } +} diff --git a/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..b71e7be8 --- /dev/null +++ b/Lesson21.CRUD_App1/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,30 @@ +package ru.alishev.springcourse.models; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + private String name; + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/Lesson21.CRUD_App1/src/main/webapp/WEB-INF/views/people/index.html b/Lesson21.CRUD_App1/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..969c4b29 --- /dev/null +++ b/Lesson21.CRUD_App1/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,14 @@ + + + + + Все люди + + + +

+ user +
+ + + \ No newline at end of file diff --git a/Lesson21.CRUD_App1/src/main/webapp/WEB-INF/views/people/show.html b/Lesson21.CRUD_App1/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..f5fd1835 --- /dev/null +++ b/Lesson21.CRUD_App1/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,11 @@ + + + + + Человек + + +

VALUE

+

VALUE

+ + \ No newline at end of file diff --git a/Lesson21_Starter.CRUD_App1/pom.xml b/Lesson21_Starter.CRUD_App1/pom.xml new file mode 100644 index 00000000..449e5457 --- /dev/null +++ b/Lesson21_Starter.CRUD_App1/pom.xml @@ -0,0 +1,106 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-crud-app1 + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson21_Starter.CRUD_App1/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson21_Starter.CRUD_App1/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson21_Starter.CRUD_App1/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson21_Starter.CRUD_App1/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson21_Starter.CRUD_App1/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson21_Starter.CRUD_App1/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson22.CRUD_App2/pom.xml b/Lesson22.CRUD_App2/pom.xml new file mode 100644 index 00000000..ad5b303f --- /dev/null +++ b/Lesson22.CRUD_App2/pom.xml @@ -0,0 +1,116 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-crud-app1 + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..17ce66e2 --- /dev/null +++ b/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,46 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") Person person) { + personDAO.save(person); + return "redirect:/people"; + } +} diff --git a/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..6ab75650 --- /dev/null +++ b/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + private List people; + + { + people = new ArrayList<>(); + + people.add(new Person(++PEOPLE_COUNT, "Tom")); + people.add(new Person(++PEOPLE_COUNT, "Bob")); + people.add(new Person(++PEOPLE_COUNT, "Mike")); + people.add(new Person(++PEOPLE_COUNT, "Katy")); + } + + public List index() { + return people; + } + + public Person show(int id) { + return people.stream().filter(person -> person.getId() == id).findAny().orElse(null); + } + + public void save(Person person) { + person.setId(++PEOPLE_COUNT); + people.add(person); + } +} diff --git a/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..7e192b38 --- /dev/null +++ b/Lesson22.CRUD_App2/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,34 @@ +package ru.alishev.springcourse.models; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + private String name; + + public Person() { + + } + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/Lesson22.CRUD_App2/src/main/webapp/WEB-INF/views/people/index.html b/Lesson22.CRUD_App2/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..ab299df5 --- /dev/null +++ b/Lesson22.CRUD_App2/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,14 @@ + + + + + Index + + + +
+ user +
+ + + \ No newline at end of file diff --git a/Lesson22.CRUD_App2/src/main/webapp/WEB-INF/views/people/new.html b/Lesson22.CRUD_App2/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..c0a6ce0b --- /dev/null +++ b/Lesson22.CRUD_App2/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,17 @@ + + + + + New person + + + +
+ + +
+ +
+ + + \ No newline at end of file diff --git a/Lesson22.CRUD_App2/src/main/webapp/WEB-INF/views/people/show.html b/Lesson22.CRUD_App2/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..5efc043e --- /dev/null +++ b/Lesson22.CRUD_App2/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,11 @@ + + + + + Show + + +

VALUE

+

VALUE

+ + \ No newline at end of file diff --git a/Lesson22_Starter.CRUD_App2/pom.xml b/Lesson22_Starter.CRUD_App2/pom.xml new file mode 100644 index 00000000..ad5b303f --- /dev/null +++ b/Lesson22_Starter.CRUD_App2/pom.xml @@ -0,0 +1,116 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-crud-app1 + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..80146ec6 --- /dev/null +++ b/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,36 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import ru.alishev.springcourse.dao.PersonDAO; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } +} diff --git a/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..04a711cc --- /dev/null +++ b/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,33 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + private List people; + + { + people = new ArrayList<>(); + + people.add(new Person(++PEOPLE_COUNT, "Tom")); + people.add(new Person(++PEOPLE_COUNT, "Bob")); + people.add(new Person(++PEOPLE_COUNT, "Mike")); + people.add(new Person(++PEOPLE_COUNT, "Katy")); + } + + public List index() { + return people; + } + + public Person show(int id) { + return people.stream().filter(person -> person.getId() == id).findAny().orElse(null); + } +} diff --git a/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..b71e7be8 --- /dev/null +++ b/Lesson22_Starter.CRUD_App2/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,30 @@ +package ru.alishev.springcourse.models; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + private String name; + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/Lesson22_Starter.CRUD_App2/src/main/webapp/WEB-INF/views/people/index.html b/Lesson22_Starter.CRUD_App2/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..969c4b29 --- /dev/null +++ b/Lesson22_Starter.CRUD_App2/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,14 @@ + + + + + Все люди + + + +
+ user +
+ + + \ No newline at end of file diff --git a/Lesson22_Starter.CRUD_App2/src/main/webapp/WEB-INF/views/people/show.html b/Lesson22_Starter.CRUD_App2/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..f5fd1835 --- /dev/null +++ b/Lesson22_Starter.CRUD_App2/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,11 @@ + + + + + Человек + + +

VALUE

+

VALUE

+ + \ No newline at end of file diff --git a/Lesson23.CRUD_App3/pom.xml b/Lesson23.CRUD_App3/pom.xml new file mode 100644 index 00000000..f1695c10 --- /dev/null +++ b/Lesson23.CRUD_App3/pom.xml @@ -0,0 +1,116 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-crud-app3 + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..65e99378 --- /dev/null +++ b/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,64 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") Person person) { + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") Person person, @PathVariable("id") int id) { + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..c00c0de2 --- /dev/null +++ b/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,48 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + private List people; + + { + people = new ArrayList<>(); + + people.add(new Person(++PEOPLE_COUNT, "Tom")); + people.add(new Person(++PEOPLE_COUNT, "Bob")); + people.add(new Person(++PEOPLE_COUNT, "Mike")); + people.add(new Person(++PEOPLE_COUNT, "Katy")); + } + + public List index() { + return people; + } + + public Person show(int id) { + return people.stream().filter(person -> person.getId() == id).findAny().orElse(null); + } + + public void save(Person person) { + person.setId(++PEOPLE_COUNT); + people.add(person); + } + + public void update(int id, Person updatedPerson) { + Person personToBeUpdated = show(id); + + personToBeUpdated.setName(updatedPerson.getName()); + } + + public void delete(int id) { + people.removeIf(p -> p.getId() == id); + } +} diff --git a/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..7e192b38 --- /dev/null +++ b/Lesson23.CRUD_App3/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,34 @@ +package ru.alishev.springcourse.models; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + private String name; + + public Person() { + + } + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..cbfd79d0 --- /dev/null +++ b/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,17 @@ + + + + + Update person + + + +
+ + +
+ +
+ + + \ No newline at end of file diff --git a/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/index.html b/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..cb4877ce --- /dev/null +++ b/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,19 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/new.html b/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..86b111fc --- /dev/null +++ b/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,17 @@ + + + + + New person + + + +
+ + +
+ +
+ + + \ No newline at end of file diff --git a/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/show.html b/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..7d251dd3 --- /dev/null +++ b/Lesson23.CRUD_App3/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,17 @@ + + + + + Show + + +

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson23_Starter.CRUD_App3/pom.xml b/Lesson23_Starter.CRUD_App3/pom.xml new file mode 100644 index 00000000..f1695c10 --- /dev/null +++ b/Lesson23_Starter.CRUD_App3/pom.xml @@ -0,0 +1,116 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-crud-app3 + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..1cf3442e --- /dev/null +++ b/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,23 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } +} diff --git a/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..17ce66e2 --- /dev/null +++ b/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,46 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") Person person) { + personDAO.save(person); + return "redirect:/people"; + } +} diff --git a/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..6ab75650 --- /dev/null +++ b/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + private List people; + + { + people = new ArrayList<>(); + + people.add(new Person(++PEOPLE_COUNT, "Tom")); + people.add(new Person(++PEOPLE_COUNT, "Bob")); + people.add(new Person(++PEOPLE_COUNT, "Mike")); + people.add(new Person(++PEOPLE_COUNT, "Katy")); + } + + public List index() { + return people; + } + + public Person show(int id) { + return people.stream().filter(person -> person.getId() == id).findAny().orElse(null); + } + + public void save(Person person) { + person.setId(++PEOPLE_COUNT); + people.add(person); + } +} diff --git a/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..7e192b38 --- /dev/null +++ b/Lesson23_Starter.CRUD_App3/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,34 @@ +package ru.alishev.springcourse.models; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + private String name; + + public Person() { + + } + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/Lesson23_Starter.CRUD_App3/src/main/webapp/WEB-INF/views/people/index.html b/Lesson23_Starter.CRUD_App3/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..ccd5bcc4 --- /dev/null +++ b/Lesson23_Starter.CRUD_App3/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,14 @@ + + + + + Index + + + +
+ user +
+ + + \ No newline at end of file diff --git a/Lesson23_Starter.CRUD_App3/src/main/webapp/WEB-INF/views/people/new.html b/Lesson23_Starter.CRUD_App3/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..86b111fc --- /dev/null +++ b/Lesson23_Starter.CRUD_App3/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,17 @@ + + + + + New person + + + +
+ + +
+ +
+ + + \ No newline at end of file diff --git a/Lesson23_Starter.CRUD_App3/src/main/webapp/WEB-INF/views/people/show.html b/Lesson23_Starter.CRUD_App3/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..f76fe8fe --- /dev/null +++ b/Lesson23_Starter.CRUD_App3/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,11 @@ + + + + + Show + + +

VALUE

+

VALUE

+ + \ No newline at end of file diff --git a/Lesson24.SpringFormsValidation/pom.xml b/Lesson24.SpringFormsValidation/pom.xml new file mode 100644 index 00000000..f27ae368 --- /dev/null +++ b/Lesson24.SpringFormsValidation/pom.xml @@ -0,0 +1,122 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-forms-validation + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..94d1fca3 --- /dev/null +++ b/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,50 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + private List people; + + { + people = new ArrayList<>(); + + people.add(new Person(++PEOPLE_COUNT, "Tom", 24, "tom@mail.ru")); + people.add(new Person(++PEOPLE_COUNT, "Bob", 52, "bob@mail.ru")); + people.add(new Person(++PEOPLE_COUNT, "Mike", 18, "mike@yahoo.com")); + people.add(new Person(++PEOPLE_COUNT, "Katy", 34, "katy@gmail.com")); + } + + public List index() { + return people; + } + + public Person show(int id) { + return people.stream().filter(person -> person.getId() == id).findAny().orElse(null); + } + + public void save(Person person) { + person.setId(++PEOPLE_COUNT); + people.add(person); + } + + public void update(int id, Person updatedPerson) { + Person personToBeUpdated = show(id); + + personToBeUpdated.setName(updatedPerson.getName()); + personToBeUpdated.setAge(updatedPerson.getAge()); + personToBeUpdated.setEmail(updatedPerson.getEmail()); + } + + public void delete(int id) { + people.removeIf(p -> p.getId() == id); + } +} diff --git a/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson24.SpringFormsValidation/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/index.html b/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/new.html b/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/show.html b/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson24.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson24_Starter.SpringFormsValidation/pom.xml b/Lesson24_Starter.SpringFormsValidation/pom.xml new file mode 100644 index 00000000..18593eaa --- /dev/null +++ b/Lesson24_Starter.SpringFormsValidation/pom.xml @@ -0,0 +1,116 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-forms-validation + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..65e99378 --- /dev/null +++ b/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,64 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") Person person) { + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") Person person, @PathVariable("id") int id) { + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..94d1fca3 --- /dev/null +++ b/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,50 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + private List people; + + { + people = new ArrayList<>(); + + people.add(new Person(++PEOPLE_COUNT, "Tom", 24, "tom@mail.ru")); + people.add(new Person(++PEOPLE_COUNT, "Bob", 52, "bob@mail.ru")); + people.add(new Person(++PEOPLE_COUNT, "Mike", 18, "mike@yahoo.com")); + people.add(new Person(++PEOPLE_COUNT, "Katy", 34, "katy@gmail.com")); + } + + public List index() { + return people; + } + + public Person show(int id) { + return people.stream().filter(person -> person.getId() == id).findAny().orElse(null); + } + + public void save(Person person) { + person.setId(++PEOPLE_COUNT); + people.add(person); + } + + public void update(int id, Person updatedPerson) { + Person personToBeUpdated = show(id); + + personToBeUpdated.setName(updatedPerson.getName()); + personToBeUpdated.setAge(updatedPerson.getAge()); + personToBeUpdated.setEmail(updatedPerson.getEmail()); + } + + public void delete(int id) { + people.removeIf(p -> p.getId() == id); + } +} diff --git a/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..ce6d186a --- /dev/null +++ b/Lesson24_Starter.SpringFormsValidation/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,54 @@ +package ru.alishev.springcourse.models; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + private String name; + private int age; + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ea9ddc84 --- /dev/null +++ b/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,23 @@ + + + + + Update person + + + +
+ + +
+ + +
+ + +
+ +
+ + + \ No newline at end of file diff --git a/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/index.html b/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/new.html b/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..40e7b9c6 --- /dev/null +++ b/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,23 @@ + + + + + New person + + + +
+ + +
+ + +
+ + +
+ +
+ + + \ No newline at end of file diff --git a/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/show.html b/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson24_Starter.SpringFormsValidation/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson25.SpringJDBC/pom.xml b/Lesson25.SpringJDBC/pom.xml new file mode 100644 index 00000000..4470af5c --- /dev/null +++ b/Lesson25.SpringJDBC/pom.xml @@ -0,0 +1,129 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-jdbc + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..c7d21b5f --- /dev/null +++ b/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,96 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + + private static final String URL = "jdbc:postgresql://localhost:5432/first_db"; + private static final String USERNAME = "postgres"; + private static final String PASSWORD = "postgres"; + + private static Connection connection; + + static { + try { + Class.forName("org.postgresql.Driver"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + try { + connection = DriverManager.getConnection(URL, USERNAME, PASSWORD); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + + public List index() { + List people = new ArrayList<>(); + + try { + Statement statement = connection.createStatement(); + String SQL = "SELECT * FROM Person"; + ResultSet resultSet = statement.executeQuery(SQL); + + while(resultSet.next()) { + Person person = new Person(); + + person.setId(resultSet.getInt("id")); + person.setName(resultSet.getString("name")); + person.setEmail(resultSet.getString("email")); + person.setAge(resultSet.getInt("age")); + + people.add(person); + } + + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + return people; + } + + public Person show(int id) { +// return people.stream().filter(person -> person.getId() == id).findAny().orElse(null); + return null; + } + + public void save(Person person) { +// person.setId(++PEOPLE_COUNT); +// people.add(person); + + try { + Statement statement = connection.createStatement(); + String SQL = "INSERT INTO Person VALUES(" + 1 + ",'" + person.getName() + + "'," + person.getAge() + ",'" + person.getEmail() + "')"; + + statement.executeUpdate(SQL); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + + } + + public void update(int id, Person updatedPerson) { +// Person personToBeUpdated = show(id); +// +// personToBeUpdated.setName(updatedPerson.getName()); +// personToBeUpdated.setAge(updatedPerson.getAge()); +// personToBeUpdated.setEmail(updatedPerson.getEmail()); + } + + public void delete(int id) { +// people.removeIf(p -> p.getId() == id); + } +} diff --git a/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson25.SpringJDBC/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/index.html b/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/new.html b/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/show.html b/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson25.SpringJDBC/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson25_Starter.SpringJDBC/pom.xml b/Lesson25_Starter.SpringJDBC/pom.xml new file mode 100644 index 00000000..756f0fea --- /dev/null +++ b/Lesson25_Starter.SpringJDBC/pom.xml @@ -0,0 +1,122 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-jdbc + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..94d1fca3 --- /dev/null +++ b/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,50 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + private List people; + + { + people = new ArrayList<>(); + + people.add(new Person(++PEOPLE_COUNT, "Tom", 24, "tom@mail.ru")); + people.add(new Person(++PEOPLE_COUNT, "Bob", 52, "bob@mail.ru")); + people.add(new Person(++PEOPLE_COUNT, "Mike", 18, "mike@yahoo.com")); + people.add(new Person(++PEOPLE_COUNT, "Katy", 34, "katy@gmail.com")); + } + + public List index() { + return people; + } + + public Person show(int id) { + return people.stream().filter(person -> person.getId() == id).findAny().orElse(null); + } + + public void save(Person person) { + person.setId(++PEOPLE_COUNT); + people.add(person); + } + + public void update(int id, Person updatedPerson) { + Person personToBeUpdated = show(id); + + personToBeUpdated.setName(updatedPerson.getName()); + personToBeUpdated.setAge(updatedPerson.getAge()); + personToBeUpdated.setEmail(updatedPerson.getEmail()); + } + + public void delete(int id) { + people.removeIf(p -> p.getId() == id); + } +} diff --git a/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson25_Starter.SpringJDBC/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/index.html b/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/new.html b/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/show.html b/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson25_Starter.SpringJDBC/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson26.SpringJDBC2/pom.xml b/Lesson26.SpringJDBC2/pom.xml new file mode 100644 index 00000000..9bc65625 --- /dev/null +++ b/Lesson26.SpringJDBC2/pom.xml @@ -0,0 +1,129 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-jdbc2 + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..07940567 --- /dev/null +++ b/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,134 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + + private static final String URL = "jdbc:postgresql://localhost:5432/first_db"; + private static final String USERNAME = "postgres"; + private static final String PASSWORD = "postgres"; + + private static Connection connection; + + static { + try { + Class.forName("org.postgresql.Driver"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + try { + connection = DriverManager.getConnection(URL, USERNAME, PASSWORD); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + + public List index() { + List people = new ArrayList<>(); + + try { + Statement statement = connection.createStatement(); + String SQL = "SELECT * FROM Person"; + ResultSet resultSet = statement.executeQuery(SQL); + + while (resultSet.next()) { + Person person = new Person(); + + person.setId(resultSet.getInt("id")); + person.setName(resultSet.getString("name")); + person.setEmail(resultSet.getString("email")); + person.setAge(resultSet.getInt("age")); + + people.add(person); + } + + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + return people; + } + + public Person show(int id) { + Person person = null; + + try { + PreparedStatement preparedStatement = + connection.prepareStatement("SELECT * FROM Person WHERE id=?"); + + preparedStatement.setInt(1, id); + + ResultSet resultSet = preparedStatement.executeQuery(); + + resultSet.next(); + + person = new Person(); + + person.setId(resultSet.getInt("id")); + person.setName(resultSet.getString("name")); + person.setEmail(resultSet.getString("email")); + person.setAge(resultSet.getInt("age")); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + return person; + } + + public void save(Person person) { + try { + PreparedStatement preparedStatement = + connection.prepareStatement("INSERT INTO Person VALUES(1, ?, ?, ?)"); + + preparedStatement.setString(1, person.getName()); + preparedStatement.setInt(2, person.getAge()); + preparedStatement.setString(3, person.getEmail()); + + preparedStatement.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + + public void update(int id, Person updatedPerson) { + try { + PreparedStatement preparedStatement = + connection.prepareStatement("UPDATE Person SET name=?, age=?, email=? WHERE id=?"); + + preparedStatement.setString(1, updatedPerson.getName()); + preparedStatement.setInt(2, updatedPerson.getAge()); + preparedStatement.setString(3, updatedPerson.getEmail()); + preparedStatement.setInt(4, id); + + preparedStatement.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + + public void delete(int id) { + PreparedStatement preparedStatement = + null; + try { + preparedStatement = connection.prepareStatement("DELETE FROM Person WHERE id=?"); + + preparedStatement.setInt(1, id); + + preparedStatement.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + } +} diff --git a/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson26.SpringJDBC2/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/index.html b/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/new.html b/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/show.html b/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson26.SpringJDBC2/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson26_Starter.SpringJDBC2/pom.xml b/Lesson26_Starter.SpringJDBC2/pom.xml new file mode 100644 index 00000000..9bc65625 --- /dev/null +++ b/Lesson26_Starter.SpringJDBC2/pom.xml @@ -0,0 +1,129 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-jdbc2 + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..c7d21b5f --- /dev/null +++ b/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,96 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + + private static final String URL = "jdbc:postgresql://localhost:5432/first_db"; + private static final String USERNAME = "postgres"; + private static final String PASSWORD = "postgres"; + + private static Connection connection; + + static { + try { + Class.forName("org.postgresql.Driver"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + try { + connection = DriverManager.getConnection(URL, USERNAME, PASSWORD); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + + public List index() { + List people = new ArrayList<>(); + + try { + Statement statement = connection.createStatement(); + String SQL = "SELECT * FROM Person"; + ResultSet resultSet = statement.executeQuery(SQL); + + while(resultSet.next()) { + Person person = new Person(); + + person.setId(resultSet.getInt("id")); + person.setName(resultSet.getString("name")); + person.setEmail(resultSet.getString("email")); + person.setAge(resultSet.getInt("age")); + + people.add(person); + } + + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + return people; + } + + public Person show(int id) { +// return people.stream().filter(person -> person.getId() == id).findAny().orElse(null); + return null; + } + + public void save(Person person) { +// person.setId(++PEOPLE_COUNT); +// people.add(person); + + try { + Statement statement = connection.createStatement(); + String SQL = "INSERT INTO Person VALUES(" + 1 + ",'" + person.getName() + + "'," + person.getAge() + ",'" + person.getEmail() + "')"; + + statement.executeUpdate(SQL); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + + } + + public void update(int id, Person updatedPerson) { +// Person personToBeUpdated = show(id); +// +// personToBeUpdated.setName(updatedPerson.getName()); +// personToBeUpdated.setAge(updatedPerson.getAge()); +// personToBeUpdated.setEmail(updatedPerson.getEmail()); + } + + public void delete(int id) { +// people.removeIf(p -> p.getId() == id); + } +} diff --git a/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson26_Starter.SpringJDBC2/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/index.html b/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/new.html b/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/show.html b/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson26_Starter.SpringJDBC2/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson27.SpringJdbcTemplate/pom.xml b/Lesson27.SpringJdbcTemplate/pom.xml new file mode 100644 index 00000000..9ca8d03f --- /dev/null +++ b/Lesson27.SpringJdbcTemplate/pom.xml @@ -0,0 +1,135 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-jdbc-template + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..642662ae --- /dev/null +++ b/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,54 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.CharacterEncodingFilter; +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.DispatcherType; +import javax.servlet.FilterRegistration; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import java.util.EnumSet; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerCharacterEncodingFilter(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } + + private void registerCharacterEncodingFilter(ServletContext aContext) { + EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD); + + CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); + characterEncodingFilter.setEncoding("UTF-8"); + characterEncodingFilter.setForceEncoding(true); + + FilterRegistration.Dynamic characterEncoding = aContext.addFilter("characterEncoding", characterEncodingFilter); + characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*"); + } +} diff --git a/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..626690e7 --- /dev/null +++ b/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,77 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + templateResolver.setCharacterEncoding("UTF-8"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + resolver.setCharacterEncoding("UTF-8"); + + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName("org.postgresql.Driver"); + dataSource.setUrl("jdbc:postgresql://localhost:5432/first_db"); + dataSource.setUsername("postgres"); + dataSource.setPassword("postgres"); + + return dataSource; + } + + @Bean + public JdbcTemplate jdbcTemplate() { + return new JdbcTemplate(dataSource()); + } +} diff --git a/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..8835bc8d --- /dev/null +++ b/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,46 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public PersonDAO(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List index() { + return jdbcTemplate.query("SELECT * FROM Person", new BeanPropertyRowMapper<>(Person.class)); + } + + public Person show(int id) { + return jdbcTemplate.query("SELECT * FROM Person WHERE id=?", new Object[]{id}, new BeanPropertyRowMapper<>(Person.class)) + .stream().findAny().orElse(null); + } + + public void save(Person person) { + jdbcTemplate.update("INSERT INTO Person VALUES(1, ?, ?, ?)", person.getName(), person.getAge(), + person.getEmail()); + } + + public void update(int id, Person updatedPerson) { + jdbcTemplate.update("UPDATE Person SET name=?, age=?, email=? WHERE id=?", updatedPerson.getName(), + updatedPerson.getAge(), updatedPerson.getEmail(), id); + } + + public void delete(int id) { + jdbcTemplate.update("DELETE FROM Person WHERE id=?", id); + } +} diff --git a/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson27.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/index.html b/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/new.html b/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/show.html b/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson27.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson27_Starter.SpringJdbcTemplate/pom.xml b/Lesson27_Starter.SpringJdbcTemplate/pom.xml new file mode 100644 index 00000000..640e8bc8 --- /dev/null +++ b/Lesson27_Starter.SpringJdbcTemplate/pom.xml @@ -0,0 +1,129 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-jdbc-template + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..a4de9f61 --- /dev/null +++ b/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } +} diff --git a/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..07940567 --- /dev/null +++ b/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,134 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + private static int PEOPLE_COUNT; + + private static final String URL = "jdbc:postgresql://localhost:5432/first_db"; + private static final String USERNAME = "postgres"; + private static final String PASSWORD = "postgres"; + + private static Connection connection; + + static { + try { + Class.forName("org.postgresql.Driver"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + try { + connection = DriverManager.getConnection(URL, USERNAME, PASSWORD); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + + public List index() { + List people = new ArrayList<>(); + + try { + Statement statement = connection.createStatement(); + String SQL = "SELECT * FROM Person"; + ResultSet resultSet = statement.executeQuery(SQL); + + while (resultSet.next()) { + Person person = new Person(); + + person.setId(resultSet.getInt("id")); + person.setName(resultSet.getString("name")); + person.setEmail(resultSet.getString("email")); + person.setAge(resultSet.getInt("age")); + + people.add(person); + } + + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + return people; + } + + public Person show(int id) { + Person person = null; + + try { + PreparedStatement preparedStatement = + connection.prepareStatement("SELECT * FROM Person WHERE id=?"); + + preparedStatement.setInt(1, id); + + ResultSet resultSet = preparedStatement.executeQuery(); + + resultSet.next(); + + person = new Person(); + + person.setId(resultSet.getInt("id")); + person.setName(resultSet.getString("name")); + person.setEmail(resultSet.getString("email")); + person.setAge(resultSet.getInt("age")); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + return person; + } + + public void save(Person person) { + try { + PreparedStatement preparedStatement = + connection.prepareStatement("INSERT INTO Person VALUES(1, ?, ?, ?)"); + + preparedStatement.setString(1, person.getName()); + preparedStatement.setInt(2, person.getAge()); + preparedStatement.setString(3, person.getEmail()); + + preparedStatement.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + + public void update(int id, Person updatedPerson) { + try { + PreparedStatement preparedStatement = + connection.prepareStatement("UPDATE Person SET name=?, age=?, email=? WHERE id=?"); + + preparedStatement.setString(1, updatedPerson.getName()); + preparedStatement.setInt(2, updatedPerson.getAge()); + preparedStatement.setString(3, updatedPerson.getEmail()); + preparedStatement.setInt(4, id); + + preparedStatement.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + + public void delete(int id) { + PreparedStatement preparedStatement = + null; + try { + preparedStatement = connection.prepareStatement("DELETE FROM Person WHERE id=?"); + + preparedStatement.setInt(1, id); + + preparedStatement.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + } +} diff --git a/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson27_Starter.SpringJdbcTemplate/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/index.html b/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/new.html b/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/show.html b/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson27_Starter.SpringJdbcTemplate/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson29.JdbcTemplateBatchUpdate/pom.xml b/Lesson29.JdbcTemplateBatchUpdate/pom.xml new file mode 100644 index 00000000..9ca8d03f --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/pom.xml @@ -0,0 +1,135 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-jdbc-template + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..c02911e9 --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,74 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName("org.postgresql.Driver"); + dataSource.setUrl("jdbc:postgresql://localhost:5432/first_db"); + dataSource.setUsername("postgres"); + dataSource.setPassword("postgres"); + + return dataSource; + } + + @Bean + public JdbcTemplate jdbcTemplate() { + return new JdbcTemplate(dataSource()); + } +} diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/controllers/BatchController.java b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/controllers/BatchController.java new file mode 100644 index 00000000..bbbeea5d --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/controllers/BatchController.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import ru.alishev.springcourse.dao.PersonDAO; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/test-batch-update") +public class BatchController { + private final PersonDAO personDAO; + + @Autowired + public BatchController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index() { + return "batch/index"; + } + + @GetMapping("/without") + public String withoutBatch() { + personDAO.testMultipleUpdate(); + return "redirect:/people"; + } + + @GetMapping("/with") + public String withBatch() { + personDAO.testBatchUpdate(); + return "redirect:/people"; + } +} diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..e6e4b662 --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,102 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public PersonDAO(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List index() { + return jdbcTemplate.query("SELECT * FROM Person", new BeanPropertyRowMapper<>(Person.class)); + } + + public Person show(int id) { + return jdbcTemplate.query("SELECT * FROM Person WHERE id=?", new Object[]{id}, new BeanPropertyRowMapper<>(Person.class)) + .stream().findAny().orElse(null); + } + + public void save(Person person) { + jdbcTemplate.update("INSERT INTO Person VALUES(1, ?, ?, ?)", person.getName(), person.getAge(), + person.getEmail()); + } + + public void update(int id, Person updatedPerson) { + jdbcTemplate.update("UPDATE Person SET name=?, age=?, email=? WHERE id=?", updatedPerson.getName(), + updatedPerson.getAge(), updatedPerson.getEmail(), id); + } + + public void delete(int id) { + jdbcTemplate.update("DELETE FROM Person WHERE id=?", id); + } + + ////////////////////// + // Тестируем производительность + ////////////////////// + + public void testMultipleUpdate() { + List people = create1000People(); + + long before = System.currentTimeMillis(); + + for (Person person : people) { + jdbcTemplate.update("INSERT INTO Person VALUES(?, ?, ?, ?)", person.getId(), person.getName(), person.getAge(), + person.getEmail()); + } + + long after = System.currentTimeMillis(); + System.out.println("Time: " + (after - before)); + } + + public void testBatchUpdate() { + List people = create1000People(); + + long before = System.currentTimeMillis(); + + jdbcTemplate.batchUpdate("INSERT INTO Person VALUES(?, ?, ?, ?)", + new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(1, people.get(i).getId()); + ps.setString(2, people.get(i).getName()); + ps.setInt(3, people.get(i).getAge()); + ps.setString(4, people.get(i).getEmail()); + } + + @Override + public int getBatchSize() { + return people.size(); + } + }); + + long after = System.currentTimeMillis(); + System.out.println("Time: " + (after - before)); + } + + private List create1000People() { + List people = new ArrayList<>(); + + for (int i = 0; i < 1000; i++) + people.add(new Person(i, "Name" + i, 30, "test" + i + "@mail.ru")); + + return people; + } +} diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/batch/index.html b/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/batch/index.html new file mode 100644 index 00000000..75aae36a --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/batch/index.html @@ -0,0 +1,14 @@ + + + + + Index + + + +Ordinary update +
+Batch update + + + \ No newline at end of file diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/index.html b/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/new.html b/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/show.html b/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson29.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson29_Starter.JdbcTemplateBatchUpdate/pom.xml b/Lesson29_Starter.JdbcTemplateBatchUpdate/pom.xml new file mode 100644 index 00000000..9ca8d03f --- /dev/null +++ b/Lesson29_Starter.JdbcTemplateBatchUpdate/pom.xml @@ -0,0 +1,135 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-jdbc-template + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..c02911e9 --- /dev/null +++ b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,74 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName("org.postgresql.Driver"); + dataSource.setUrl("jdbc:postgresql://localhost:5432/first_db"); + dataSource.setUsername("postgres"); + dataSource.setPassword("postgres"); + + return dataSource; + } + + @Bean + public JdbcTemplate jdbcTemplate() { + return new JdbcTemplate(dataSource()); + } +} diff --git a/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..8835bc8d --- /dev/null +++ b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,46 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public PersonDAO(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List index() { + return jdbcTemplate.query("SELECT * FROM Person", new BeanPropertyRowMapper<>(Person.class)); + } + + public Person show(int id) { + return jdbcTemplate.query("SELECT * FROM Person WHERE id=?", new Object[]{id}, new BeanPropertyRowMapper<>(Person.class)) + .stream().findAny().orElse(null); + } + + public void save(Person person) { + jdbcTemplate.update("INSERT INTO Person VALUES(1, ?, ?, ?)", person.getName(), person.getAge(), + person.getEmail()); + } + + public void update(int id, Person updatedPerson) { + jdbcTemplate.update("UPDATE Person SET name=?, age=?, email=? WHERE id=?", updatedPerson.getName(), + updatedPerson.getAge(), updatedPerson.getEmail(), id); + } + + public void delete(int id) { + jdbcTemplate.update("DELETE FROM Person WHERE id=?", id); + } +} diff --git a/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/index.html b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/new.html b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/show.html b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson29_Starter.JdbcTemplateBatchUpdate/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson30.DBAutoIncrement/pom.xml b/Lesson30.DBAutoIncrement/pom.xml new file mode 100644 index 00000000..9ca8d03f --- /dev/null +++ b/Lesson30.DBAutoIncrement/pom.xml @@ -0,0 +1,135 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-jdbc-template + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..c02911e9 --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,74 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName("org.postgresql.Driver"); + dataSource.setUrl("jdbc:postgresql://localhost:5432/first_db"); + dataSource.setUsername("postgres"); + dataSource.setPassword("postgres"); + + return dataSource; + } + + @Bean + public JdbcTemplate jdbcTemplate() { + return new JdbcTemplate(dataSource()); + } +} diff --git a/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/controllers/BatchController.java b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/controllers/BatchController.java new file mode 100644 index 00000000..bbbeea5d --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/controllers/BatchController.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import ru.alishev.springcourse.dao.PersonDAO; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/test-batch-update") +public class BatchController { + private final PersonDAO personDAO; + + @Autowired + public BatchController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index() { + return "batch/index"; + } + + @GetMapping("/without") + public String withoutBatch() { + personDAO.testMultipleUpdate(); + return "redirect:/people"; + } + + @GetMapping("/with") + public String withBatch() { + personDAO.testBatchUpdate(); + return "redirect:/people"; + } +} diff --git a/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..e7fe7300 --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,102 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public PersonDAO(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List index() { + return jdbcTemplate.query("SELECT * FROM Person", new BeanPropertyRowMapper<>(Person.class)); + } + + public Person show(int id) { + return jdbcTemplate.query("SELECT * FROM Person WHERE id=?", new Object[]{id}, new BeanPropertyRowMapper<>(Person.class)) + .stream().findAny().orElse(null); + } + + public void save(Person person) { + jdbcTemplate.update("INSERT INTO Person(name, age, email) VALUES(?, ?, ?)", person.getName(), person.getAge(), + person.getEmail()); + } + + public void update(int id, Person updatedPerson) { + jdbcTemplate.update("UPDATE Person SET name=?, age=?, email=? WHERE id=?", updatedPerson.getName(), + updatedPerson.getAge(), updatedPerson.getEmail(), id); + } + + public void delete(int id) { + jdbcTemplate.update("DELETE FROM Person WHERE id=?", id); + } + + ////////////////////// + // Тестируем производительность + ////////////////////// + + public void testMultipleUpdate() { + List people = create1000People(); + + long before = System.currentTimeMillis(); + + for (Person person : people) { + jdbcTemplate.update("INSERT INTO Person VALUES(?, ?, ?, ?)", person.getId(), person.getName(), person.getAge(), + person.getEmail()); + } + + long after = System.currentTimeMillis(); + System.out.println("Time: " + (after - before)); + } + + public void testBatchUpdate() { + List people = create1000People(); + + long before = System.currentTimeMillis(); + + jdbcTemplate.batchUpdate("INSERT INTO Person VALUES(?, ?, ?, ?)", + new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(1, people.get(i).getId()); + ps.setString(2, people.get(i).getName()); + ps.setInt(3, people.get(i).getAge()); + ps.setString(4, people.get(i).getEmail()); + } + + @Override + public int getBatchSize() { + return people.size(); + } + }); + + long after = System.currentTimeMillis(); + System.out.println("Time: " + (after - before)); + } + + private List create1000People() { + List people = new ArrayList<>(); + + for (int i = 0; i < 1000; i++) + people.add(new Person(i, "Name" + i, 30, "test" + i + "@mail.ru")); + + return people; + } +} diff --git a/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/batch/index.html b/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/batch/index.html new file mode 100644 index 00000000..75aae36a --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/batch/index.html @@ -0,0 +1,14 @@ + + + + + Index + + + +Ordinary update +
+Batch update + + + \ No newline at end of file diff --git a/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/index.html b/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/new.html b/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/show.html b/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson30.DBAutoIncrement/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson39.SpringValidator/pom.xml b/Lesson39.SpringValidator/pom.xml new file mode 100644 index 00000000..5830dd4d --- /dev/null +++ b/Lesson39.SpringValidator/pom.xml @@ -0,0 +1,135 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-app + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..c02911e9 --- /dev/null +++ b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,74 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName("org.postgresql.Driver"); + dataSource.setUrl("jdbc:postgresql://localhost:5432/first_db"); + dataSource.setUsername("postgres"); + dataSource.setPassword("postgres"); + + return dataSource; + } + + @Bean + public JdbcTemplate jdbcTemplate() { + return new JdbcTemplate(dataSource()); + } +} diff --git a/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/controllers/BatchController.java b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/controllers/BatchController.java new file mode 100644 index 00000000..bbbeea5d --- /dev/null +++ b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/controllers/BatchController.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import ru.alishev.springcourse.dao.PersonDAO; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/test-batch-update") +public class BatchController { + private final PersonDAO personDAO; + + @Autowired + public BatchController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index() { + return "batch/index"; + } + + @GetMapping("/without") + public String withoutBatch() { + personDAO.testMultipleUpdate(); + return "redirect:/people"; + } + + @GetMapping("/with") + public String withBatch() { + personDAO.testBatchUpdate(); + return "redirect:/people"; + } +} diff --git a/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..19cc3bf3 --- /dev/null +++ b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,81 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; +import ru.alishev.springcourse.util.PersonValidator; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + private final PersonValidator personValidator; + + @Autowired + public PeopleController(PersonDAO personDAO, PersonValidator personValidator) { + this.personDAO = personDAO; + this.personValidator = personValidator; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + + personValidator.validate(person, bindingResult); + + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..050f00ba --- /dev/null +++ b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,108 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public PersonDAO(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List index() { + return jdbcTemplate.query("SELECT * FROM Person", new BeanPropertyRowMapper<>(Person.class)); + } + + public Optional show(String email) { + return jdbcTemplate.query("SELECT * FROM Person WHERE email=?", new Object[]{email}, + new BeanPropertyRowMapper<>(Person.class)).stream().findAny(); + } + + public Person show(int id) { + return jdbcTemplate.query("SELECT * FROM Person WHERE id=?", new Object[]{id}, new BeanPropertyRowMapper<>(Person.class)) + .stream().findAny().orElse(null); + } + + public void save(Person person) { + jdbcTemplate.update("INSERT INTO Person(name, age, email) VALUES(?, ?, ?)", person.getName(), person.getAge(), + person.getEmail()); + } + + public void update(int id, Person updatedPerson) { + jdbcTemplate.update("UPDATE Person SET name=?, age=?, email=? WHERE id=?", updatedPerson.getName(), + updatedPerson.getAge(), updatedPerson.getEmail(), id); + } + + public void delete(int id) { + jdbcTemplate.update("DELETE FROM Person WHERE id=?", id); + } + + ////////////////////// + // Тестируем производительность + ////////////////////// + + public void testMultipleUpdate() { + List people = create1000People(); + + long before = System.currentTimeMillis(); + + for (Person person : people) { + jdbcTemplate.update("INSERT INTO Person VALUES(?, ?, ?, ?)", person.getId(), person.getName(), person.getAge(), + person.getEmail()); + } + + long after = System.currentTimeMillis(); + System.out.println("Time: " + (after - before)); + } + + public void testBatchUpdate() { + List people = create1000People(); + + long before = System.currentTimeMillis(); + + jdbcTemplate.batchUpdate("INSERT INTO Person VALUES(?, ?, ?, ?)", + new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(1, people.get(i).getId()); + ps.setString(2, people.get(i).getName()); + ps.setInt(3, people.get(i).getAge()); + ps.setString(4, people.get(i).getEmail()); + } + + @Override + public int getBatchSize() { + return people.size(); + } + }); + + long after = System.currentTimeMillis(); + System.out.println("Time: " + (after - before)); + } + + private List create1000People() { + List people = new ArrayList<>(); + + for (int i = 0; i < 1000; i++) + people.add(new Person(i, "Name" + i, 30, "test" + i + "@mail.ru")); + + return people; + } +} diff --git a/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/util/PersonValidator.java b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/util/PersonValidator.java new file mode 100644 index 00000000..94633511 --- /dev/null +++ b/Lesson39.SpringValidator/src/main/java/ru/alishev/springcourse/util/PersonValidator.java @@ -0,0 +1,42 @@ +package ru.alishev.springcourse.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +/** + * @author Neil Alishev + */ +@Component +public class PersonValidator implements Validator { + + private final PersonDAO personDAO; + + @Autowired + public PersonValidator(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @Override + public boolean supports(Class aClass) { + return Person.class.equals(aClass); + } + + @Override + public void validate(Object o, Errors errors) { + Person person = (Person) o; + + if (personDAO.show(person.getEmail()).isPresent()) { + // поле, код ошибки, сообщение ошибки + errors.rejectValue("email", "", "This email is already in use"); + } + + // Проверяем, что у человека имя начинается с заглавной буквы + // Если имя не начинается с заглавной буквы - выдаем ошибку + if (!Character.isUpperCase(person.getName().codePointAt(0))) + errors.rejectValue("name", "", "Name should start with a capital letter"); + } +} diff --git a/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/batch/index.html b/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/batch/index.html new file mode 100644 index 00000000..75aae36a --- /dev/null +++ b/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/batch/index.html @@ -0,0 +1,14 @@ + + + + + Index + + + +Ordinary update +
+Batch update + + + \ No newline at end of file diff --git a/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/index.html b/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/new.html b/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/show.html b/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson39.SpringValidator/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson40.PatternValidation/pom.xml b/Lesson40.PatternValidation/pom.xml new file mode 100644 index 00000000..5830dd4d --- /dev/null +++ b/Lesson40.PatternValidation/pom.xml @@ -0,0 +1,135 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-app + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..63582e9f --- /dev/null +++ b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } +} diff --git a/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..c02911e9 --- /dev/null +++ b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,74 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName("org.postgresql.Driver"); + dataSource.setUrl("jdbc:postgresql://localhost:5432/first_db"); + dataSource.setUsername("postgres"); + dataSource.setPassword("postgres"); + + return dataSource; + } + + @Bean + public JdbcTemplate jdbcTemplate() { + return new JdbcTemplate(dataSource()); + } +} diff --git a/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/controllers/BatchController.java b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/controllers/BatchController.java new file mode 100644 index 00000000..bbbeea5d --- /dev/null +++ b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/controllers/BatchController.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import ru.alishev.springcourse.dao.PersonDAO; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/test-batch-update") +public class BatchController { + private final PersonDAO personDAO; + + @Autowired + public BatchController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index() { + return "batch/index"; + } + + @GetMapping("/without") + public String withoutBatch() { + personDAO.testMultipleUpdate(); + return "redirect:/people"; + } + + @GetMapping("/with") + public String withBatch() { + personDAO.testBatchUpdate(); + return "redirect:/people"; + } +} diff --git a/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..19cc3bf3 --- /dev/null +++ b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,81 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; +import ru.alishev.springcourse.util.PersonValidator; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + private final PersonValidator personValidator; + + @Autowired + public PeopleController(PersonDAO personDAO, PersonValidator personValidator) { + this.personDAO = personDAO; + this.personValidator = personValidator; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + + personValidator.validate(person, bindingResult); + + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..6f2bbeb6 --- /dev/null +++ b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,108 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public PersonDAO(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List index() { + return jdbcTemplate.query("SELECT * FROM Person", new BeanPropertyRowMapper<>(Person.class)); + } + + public Optional show(String email) { + return jdbcTemplate.query("SELECT * FROM Person WHERE email=?", new Object[]{email}, + new BeanPropertyRowMapper<>(Person.class)).stream().findAny(); + } + + public Person show(int id) { + return jdbcTemplate.query("SELECT * FROM Person WHERE id=?", new Object[]{id}, new BeanPropertyRowMapper<>(Person.class)) + .stream().findAny().orElse(null); + } + + public void save(Person person) { + jdbcTemplate.update("INSERT INTO Person(name, age, email, address) VALUES(?, ?, ?, ?)", person.getName(), person.getAge(), + person.getEmail(), person.getAddress()); + } + + public void update(int id, Person updatedPerson) { + jdbcTemplate.update("UPDATE Person SET name=?, age=?, email=?, address=? WHERE id=?", updatedPerson.getName(), + updatedPerson.getAge(), updatedPerson.getEmail(), updatedPerson.getAddress(), id); + } + + public void delete(int id) { + jdbcTemplate.update("DELETE FROM Person WHERE id=?", id); + } + + ////////////////////// + // Тестируем производительность + ////////////////////// + + public void testMultipleUpdate() { + List people = create1000People(); + + long before = System.currentTimeMillis(); + + for (Person person : people) { + jdbcTemplate.update("INSERT INTO Person VALUES(?, ?, ?, ?)", person.getId(), person.getName(), person.getAge(), + person.getEmail()); + } + + long after = System.currentTimeMillis(); + System.out.println("Time: " + (after - before)); + } + + public void testBatchUpdate() { + List people = create1000People(); + + long before = System.currentTimeMillis(); + + jdbcTemplate.batchUpdate("INSERT INTO Person VALUES(?, ?, ?, ?)", + new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(1, people.get(i).getId()); + ps.setString(2, people.get(i).getName()); + ps.setInt(3, people.get(i).getAge()); + ps.setString(4, people.get(i).getEmail()); + } + + @Override + public int getBatchSize() { + return people.size(); + } + }); + + long after = System.currentTimeMillis(); + System.out.println("Time: " + (after - before)); + } + + private List create1000People() { + List people = new ArrayList<>(); + + for (int i = 0; i < 1000; i++) + people.add(new Person(i, "Name" + i, 30, "test" + i + "@mail.ru", "some address")); + + return people; + } +} diff --git a/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..c21e1b3f --- /dev/null +++ b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,78 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.*; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + // Страна, Город, Индекс (6 цифр) + // Russia, Moscow, 123456 + @Pattern(regexp = "[A-Z]\\w+, [A-Z]\\w+, \\d{6}", message = "Your address should be in this format: Country, City, Postal Code (6 digits)") + private String address; + + public Person() { + + } + + public Person(int id, String name, int age, String email, String address) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + this.address = address; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } +} diff --git a/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/util/PersonValidator.java b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/util/PersonValidator.java new file mode 100644 index 00000000..94633511 --- /dev/null +++ b/Lesson40.PatternValidation/src/main/java/ru/alishev/springcourse/util/PersonValidator.java @@ -0,0 +1,42 @@ +package ru.alishev.springcourse.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +/** + * @author Neil Alishev + */ +@Component +public class PersonValidator implements Validator { + + private final PersonDAO personDAO; + + @Autowired + public PersonValidator(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @Override + public boolean supports(Class aClass) { + return Person.class.equals(aClass); + } + + @Override + public void validate(Object o, Errors errors) { + Person person = (Person) o; + + if (personDAO.show(person.getEmail()).isPresent()) { + // поле, код ошибки, сообщение ошибки + errors.rejectValue("email", "", "This email is already in use"); + } + + // Проверяем, что у человека имя начинается с заглавной буквы + // Если имя не начинается с заглавной буквы - выдаем ошибку + if (!Character.isUpperCase(person.getName().codePointAt(0))) + errors.rejectValue("name", "", "Name should start with a capital letter"); + } +} diff --git a/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/batch/index.html b/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/batch/index.html new file mode 100644 index 00000000..75aae36a --- /dev/null +++ b/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/batch/index.html @@ -0,0 +1,14 @@ + + + + + Index + + + +Ordinary update +
+Batch update + + + \ No newline at end of file diff --git a/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..64890f33 --- /dev/null +++ b/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,30 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ + +
Address Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/index.html b/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/new.html b/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..9cb84c61 --- /dev/null +++ b/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,30 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ + +
Address Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/show.html b/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson40.PatternValidation/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson41.SelectOption/pom.xml b/Lesson41.SelectOption/pom.xml new file mode 100644 index 00000000..5830dd4d --- /dev/null +++ b/Lesson41.SelectOption/pom.xml @@ -0,0 +1,135 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-app + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..642662ae --- /dev/null +++ b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,54 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.CharacterEncodingFilter; +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.DispatcherType; +import javax.servlet.FilterRegistration; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import java.util.EnumSet; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerCharacterEncodingFilter(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); + } + + private void registerCharacterEncodingFilter(ServletContext aContext) { + EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD); + + CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); + characterEncodingFilter.setEncoding("UTF-8"); + characterEncodingFilter.setForceEncoding(true); + + FilterRegistration.Dynamic characterEncoding = aContext.addFilter("characterEncoding", characterEncodingFilter); + characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*"); + } +} diff --git a/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..626690e7 --- /dev/null +++ b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,77 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + @Autowired + public SpringConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + templateResolver.setCharacterEncoding("UTF-8"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + resolver.setCharacterEncoding("UTF-8"); + + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName("org.postgresql.Driver"); + dataSource.setUrl("jdbc:postgresql://localhost:5432/first_db"); + dataSource.setUsername("postgres"); + dataSource.setPassword("postgres"); + + return dataSource; + } + + @Bean + public JdbcTemplate jdbcTemplate() { + return new JdbcTemplate(dataSource()); + } +} diff --git a/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/controllers/AdminController.java b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/controllers/AdminController.java new file mode 100644 index 00000000..e136b223 --- /dev/null +++ b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/controllers/AdminController.java @@ -0,0 +1,37 @@ +package ru.alishev.springcourse.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/admin") +public class AdminController { + + private final PersonDAO personDAO; + + @Autowired + public AdminController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String adminPage(Model model, @ModelAttribute("person") Person person) { + model.addAttribute("people", personDAO.index()); + + return "adminPage"; + } + + @PatchMapping("/add") + public String makeAdmin(@ModelAttribute("person") Person person) { + System.out.println(person.getId()); + + return "redirect:/people"; + } +} diff --git a/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..610ca19e --- /dev/null +++ b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,46 @@ +package ru.alishev.springcourse.dao; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.alishev.springcourse.models.Person; + +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public PersonDAO(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List index() { + return jdbcTemplate.query("SELECT * FROM Person", new BeanPropertyRowMapper<>(Person.class)); + } + + public Person show(int id) { + return jdbcTemplate.query("SELECT * FROM Person WHERE id=?", new Object[]{id}, new BeanPropertyRowMapper<>(Person.class)) + .stream().findAny().orElse(null); + } + + public void save(Person person) { + jdbcTemplate.update("INSERT INTO Person(name, age, email) VALUES(?, ?, ?)", person.getName(), person.getAge(), + person.getEmail()); + } + + public void update(int id, Person updatedPerson) { + jdbcTemplate.update("UPDATE Person SET name=?, age=?, email=? WHERE id=?", updatedPerson.getName(), + updatedPerson.getAge(), updatedPerson.getEmail(), id); + } + + public void delete(int id) { + jdbcTemplate.update("DELETE FROM Person WHERE id=?", id); + } +} diff --git a/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/models/Person.java b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..4b9b5b57 --- /dev/null +++ b/Lesson41.SelectOption/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,67 @@ +package ru.alishev.springcourse.models; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +public class Person { + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + private int age; + + @NotEmpty(message = "Email should not be empty") + @Email(message = "Email should be valid") + private String email; + + public Person() { + + } + + public Person(int id, String name, int age, String email) { + this.id = id; + this.name = name; + this.age = age; + this.email = email; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/adminPage.html b/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/adminPage.html new file mode 100644 index 00000000..d4f908b3 --- /dev/null +++ b/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/adminPage.html @@ -0,0 +1,20 @@ + + + + + Назначить администратора + + + +
+ + + + +
+ + + \ No newline at end of file diff --git a/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/edit.html b/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/index.html b/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/new.html b/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/show.html b/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/Lesson41.SelectOption/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/Lesson8.InitDestroyAndFactory/.gitignore b/Lesson8.InitDestroyAndFactory/.gitignore new file mode 100644 index 00000000..a5982c10 --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/.gitignore @@ -0,0 +1,111 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar + diff --git a/Lesson8.InitDestroyAndFactory/pom.xml b/Lesson8.InitDestroyAndFactory/pom.xml new file mode 100644 index 00000000..9700f963 --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + ru.alishev.springcourse + InitDestroyAndFactory + 1.0-SNAPSHOT + war + + spring-ioc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + 5.1.4.RELEASE + + + + + org.springframework + spring-beans + 5.1.4.RELEASE + + + + + org.springframework + spring-context + 5.1.4.RELEASE + + + + + spring-ioc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/ClassicalMusic.java b/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/ClassicalMusic.java new file mode 100644 index 00000000..34483e20 --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/ClassicalMusic.java @@ -0,0 +1,25 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public class ClassicalMusic implements Music { + private ClassicalMusic() {} + + public static ClassicalMusic getClassicalMusic() { + return new ClassicalMusic(); + } + + public void doMyInit() { + System.out.println("Doing my initialization"); + } + + public void doMyDestroy() { + System.out.println("Doing my destruction"); + } + + @Override + public String getSong() { + return "Hungarian Rhapsody"; + } +} diff --git a/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/Music.java b/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/Music.java new file mode 100644 index 00000000..3fe962a1 --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/Music.java @@ -0,0 +1,8 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public interface Music { + String getSong(); +} diff --git a/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/MusicPlayer.java b/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/MusicPlayer.java new file mode 100644 index 00000000..56d941fa --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/MusicPlayer.java @@ -0,0 +1,42 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public class MusicPlayer { + private Music music; + + private String name; + private int volume; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getVolume() { + return volume; + } + + public void setVolume(int volume) { + this.volume = volume; + } + + // IoC + public MusicPlayer(Music music) { + this.music = music; + } + + public MusicPlayer() {} + + public void setMusic(Music music) { + this.music = music; + } + + public void playMusic() { + System.out.println("Playing: " + music.getSong()); + } +} diff --git a/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/RockMusic.java b/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/RockMusic.java new file mode 100644 index 00000000..cccc5700 --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/RockMusic.java @@ -0,0 +1,11 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public class RockMusic implements Music { + @Override + public String getSong() { + return "Wind cries Mary"; + } +} diff --git a/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/TestSpring.java b/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/TestSpring.java new file mode 100644 index 00000000..432252f5 --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/src/main/java/ru/alishev/springcourse/TestSpring.java @@ -0,0 +1,38 @@ +package ru.alishev.springcourse; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Neil Alishev + */ +public class TestSpring { + public static void main(String[] args) { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "applicationContext.xml" + ); + + ClassicalMusic classicalMusic = context.getBean("musicBean", ClassicalMusic.class); + + System.out.println(classicalMusic.getSong()); + +// MusicPlayer firstMusicPlayer = context.getBean("musicPlayer", MusicPlayer.class); +// MusicPlayer secondMusicPlayer = context.getBean("musicPlayer", MusicPlayer.class); +// +// boolean comparison = firstMusicPlayer == secondMusicPlayer; +// +// System.out.println(comparison); +// +// System.out.println(firstMusicPlayer); +// System.out.println(secondMusicPlayer); +// +// firstMusicPlayer.setVolume(10); +// +// System.out.println(firstMusicPlayer.getVolume()); +// System.out.println(secondMusicPlayer.getVolume()); + + //System.out.println(musicPlayer.getName()); + //System.out.println(musicPlayer.getVolume()); + + context.close(); + } +} diff --git a/Lesson8.InitDestroyAndFactory/src/main/resources/applicationContext.xml b/Lesson8.InitDestroyAndFactory/src/main/resources/applicationContext.xml new file mode 100644 index 00000000..72a1af4b --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/src/main/resources/applicationContext.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Lesson8.InitDestroyAndFactory/src/main/resources/musicPlayer.properties b/Lesson8.InitDestroyAndFactory/src/main/resources/musicPlayer.properties new file mode 100644 index 00000000..7087681d --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/src/main/resources/musicPlayer.properties @@ -0,0 +1,2 @@ +musicPlayer.name=Some name +musicPlayer.volume=70 \ No newline at end of file diff --git a/Lesson8.InitDestroyAndFactory/src/main/webapp/WEB-INF/web.xml b/Lesson8.InitDestroyAndFactory/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..9f88c1f9 --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/Lesson8.InitDestroyAndFactory/src/main/webapp/index.jsp b/Lesson8.InitDestroyAndFactory/src/main/webapp/index.jsp new file mode 100644 index 00000000..c38169bb --- /dev/null +++ b/Lesson8.InitDestroyAndFactory/src/main/webapp/index.jsp @@ -0,0 +1,5 @@ + + +

Hello World!

+ + diff --git a/Lesson9.SpringAnnotations1/.gitignore b/Lesson9.SpringAnnotations1/.gitignore new file mode 100644 index 00000000..a5982c10 --- /dev/null +++ b/Lesson9.SpringAnnotations1/.gitignore @@ -0,0 +1,111 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar + diff --git a/Lesson9.SpringAnnotations1/pom.xml b/Lesson9.SpringAnnotations1/pom.xml new file mode 100644 index 00000000..52f3de45 --- /dev/null +++ b/Lesson9.SpringAnnotations1/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + ru.alishev.springcourse + SpringAnnotations1 + 1.0-SNAPSHOT + war + + spring-ioc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + 5.1.4.RELEASE + + + + + org.springframework + spring-beans + 5.1.4.RELEASE + + + + + org.springframework + spring-context + 5.1.4.RELEASE + + + + + spring-ioc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/ClassicalMusic.java b/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/ClassicalMusic.java new file mode 100644 index 00000000..daaf7968 --- /dev/null +++ b/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/ClassicalMusic.java @@ -0,0 +1,14 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class ClassicalMusic implements Music { + @Override + public String getSong() { + return "Hungarian Rhapsody"; + } +} diff --git a/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/Music.java b/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/Music.java new file mode 100644 index 00000000..3fe962a1 --- /dev/null +++ b/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/Music.java @@ -0,0 +1,8 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public interface Music { + String getSong(); +} diff --git a/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/MusicPlayer.java b/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/MusicPlayer.java new file mode 100644 index 00000000..9c070471 --- /dev/null +++ b/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/MusicPlayer.java @@ -0,0 +1,17 @@ +package ru.alishev.springcourse; + +/** + * @author Neil Alishev + */ +public class MusicPlayer { + private Music music; + + // IoC + public MusicPlayer(Music music) { + this.music = music; + } + + public void playMusic() { + System.out.println("Playing: " + music.getSong()); + } +} diff --git a/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/RockMusic.java b/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/RockMusic.java new file mode 100644 index 00000000..5b5acc34 --- /dev/null +++ b/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/RockMusic.java @@ -0,0 +1,14 @@ +package ru.alishev.springcourse; + +import org.springframework.stereotype.Component; + +/** + * @author Neil Alishev + */ +@Component +public class RockMusic implements Music { + @Override + public String getSong() { + return "Wind cries Mary"; + } +} diff --git a/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/TestSpring.java b/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/TestSpring.java new file mode 100644 index 00000000..dbf6456c --- /dev/null +++ b/Lesson9.SpringAnnotations1/src/main/java/ru/alishev/springcourse/TestSpring.java @@ -0,0 +1,28 @@ +package ru.alishev.springcourse; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Neil Alishev + */ +public class TestSpring { + public static void main(String[] args) { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( + "applicationContext.xml" + ); + + Music music = context.getBean("rockMusic", Music.class); + + MusicPlayer musicPlayer = new MusicPlayer(music); + + musicPlayer.playMusic(); + + Music music2 = context.getBean("classicalMusic", Music.class); + + MusicPlayer classicalMusicPlayer = new MusicPlayer(music2); + + classicalMusicPlayer.playMusic(); + + context.close(); + } +} diff --git a/Lesson9.SpringAnnotations1/src/main/resources/applicationContext.xml b/Lesson9.SpringAnnotations1/src/main/resources/applicationContext.xml new file mode 100644 index 00000000..6fcc7b1a --- /dev/null +++ b/Lesson9.SpringAnnotations1/src/main/resources/applicationContext.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/Lesson9.SpringAnnotations1/src/main/webapp/WEB-INF/web.xml b/Lesson9.SpringAnnotations1/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..9f88c1f9 --- /dev/null +++ b/Lesson9.SpringAnnotations1/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/Lesson9.SpringAnnotations1/src/main/webapp/index.jsp b/Lesson9.SpringAnnotations1/src/main/webapp/index.jsp new file mode 100644 index 00000000..c38169bb --- /dev/null +++ b/Lesson9.SpringAnnotations1/src/main/webapp/index.jsp @@ -0,0 +1,5 @@ + + +

Hello World!

+ + diff --git a/README.md b/README.md index 6acee030..dcb66b76 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Код из курса по Spring Framework +# Код из курса по Spring Framework (https://www.youtube.com/playlist?list=PLAma_mKffTOR5o0WNHnY0mTjKxnCgSXrZ) ## Инструкции по запуску @@ -22,4 +22,5 @@ git clone git@github.com:NeilAlishev/SpringCourse.git ### Для Web - приложений (Spring MVC) -Будут добавлены позже, когда появятся уроки по Spring MVC + +Все так же, как и у базовых Spring приложений, за исключением того, что надо настроить сервер. Эта процедура показана в этом уроке - https://www.youtube.com/watch?v=BgE5DoIN6Bs diff --git a/SpringDataJPACRUDApp/pom.xml b/SpringDataJPACRUDApp/pom.xml new file mode 100644 index 00000000..76c7425d --- /dev/null +++ b/SpringDataJPACRUDApp/pom.xml @@ -0,0 +1,159 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-data-jpa-crud-app + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.3.5 + 5.4.28.Final + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + + + org.springframework + spring-orm + ${spring.version} + + + + + org.springframework.data + spring-data-jpa + 2.4.7 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..dba65f7d --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,54 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.CharacterEncodingFilter; +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.DispatcherType; +import javax.servlet.FilterRegistration; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import java.util.EnumSet; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerCharacterEncodingFilter(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null, true, "/*"); + } + + private void registerCharacterEncodingFilter(ServletContext aContext) { + EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD); + + CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); + characterEncodingFilter.setEncoding("UTF-8"); + characterEncodingFilter.setForceEncoding(true); + + FilterRegistration.Dynamic characterEncoding = aContext.addFilter("characterEncoding", characterEncodingFilter); + characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*"); + } +} diff --git a/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..37986ef9 --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,115 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; +import java.util.Properties; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@PropertySource("classpath:hibernate.properties") +@EnableTransactionManagement +@EnableJpaRepositories("ru.alishev.springcourse.repositories") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + private final Environment env; + + @Autowired + public SpringConfig(ApplicationContext applicationContext, Environment env) { + this.applicationContext = applicationContext; + this.env = env; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + templateResolver.setCharacterEncoding("UTF-8"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + resolver.setCharacterEncoding("UTF-8"); + + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName(env.getRequiredProperty("hibernate.driver_class")); + dataSource.setUrl(env.getRequiredProperty("hibernate.connection.url")); + dataSource.setUsername(env.getRequiredProperty("hibernate.connection.username")); + dataSource.setPassword(env.getRequiredProperty("hibernate.connection.password")); + + return dataSource; + } + + private Properties hibernateProperties() { + Properties properties = new Properties(); + properties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect")); + properties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql")); + + return properties; + } + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource()); + em.setPackagesToScan("ru.alishev.springcourse.models"); + + final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + em.setJpaVendorAdapter(vendorAdapter); + em.setJpaProperties(hibernateProperties()); + + return em; + } + + @Bean + public PlatformTransactionManager transactionManager() { + JpaTransactionManager transactionManager = new JpaTransactionManager(); + transactionManager.setEntityManagerFactory(entityManagerFactory().getObject()); + + return transactionManager; + } +} diff --git a/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..867ba974 --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.models.Person; +import ru.alishev.springcourse.services.PeopleService; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PeopleService peopleService; + + @Autowired + public PeopleController(PeopleService peopleService) { + this.peopleService = peopleService; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", peopleService.findAll()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", peopleService.findOne(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + peopleService.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", peopleService.findOne(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + peopleService.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + peopleService.delete(id); + return "redirect:/people"; + } +} diff --git a/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/models/Person.java b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..beddd581 --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,83 @@ +package ru.alishev.springcourse.models; + +import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +@Entity +@Table(name = "Person") +public class Person { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + @Column(name = "name") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + @Column(name = "age") + private int age; + + @Column(name = "email") + @NotEmpty(message = "Email should not be empty") + @Email + private String email; + + public Person() { + + } + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/repositories/PeopleRepository.java b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/repositories/PeopleRepository.java new file mode 100644 index 00000000..5f2cf5fa --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/repositories/PeopleRepository.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.alishev.springcourse.models.Person; + +/** + * @author Neil Alishev + */ +@Repository +public interface PeopleRepository extends JpaRepository { + +} diff --git a/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/services/PeopleService.java b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/services/PeopleService.java new file mode 100644 index 00000000..f71173b8 --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/java/ru/alishev/springcourse/services/PeopleService.java @@ -0,0 +1,50 @@ +package ru.alishev.springcourse.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.alishev.springcourse.models.Person; +import ru.alishev.springcourse.repositories.PeopleRepository; + +import java.util.List; +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Service +@Transactional(readOnly = true) +public class PeopleService { + + private final PeopleRepository peopleRepository; + + @Autowired + public PeopleService(PeopleRepository peopleRepository) { + this.peopleRepository = peopleRepository; + } + + public List findAll() { + return peopleRepository.findAll(); + } + + public Person findOne(int id) { + Optional foundPerson = peopleRepository.findById(id); + return foundPerson.orElse(null); + } + + @Transactional + public void save(Person person) { + peopleRepository.save(person); + } + + @Transactional + public void update(int id, Person updatedPerson) { + updatedPerson.setId(id); + peopleRepository.save(updatedPerson); + } + + @Transactional + public void delete(int id) { + peopleRepository.deleteById(id); + } +} diff --git a/SpringDataJPACRUDApp/src/main/resources/hibernate.properties b/SpringDataJPACRUDApp/src/main/resources/hibernate.properties new file mode 100644 index 00000000..69717fea --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/resources/hibernate.properties @@ -0,0 +1,9 @@ +# Конфигурация источника данных (Data Source) +hibernate.driver_class=org.postgresql.Driver +hibernate.connection.url=jdbc:postgresql://localhost:5432/hibernate_demo_db +hibernate.connection.username=postgres +hibernate.connection.password=postgres + +# Конфигурация самого Hibernate +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +hibernate.show_sql=true \ No newline at end of file diff --git a/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/edit.html b/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/index.html b/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/new.html b/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/show.html b/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/SpringDataJPACRUDApp/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/SpringDateTime/pom.xml b/SpringDateTime/pom.xml new file mode 100644 index 00000000..7d8e963b --- /dev/null +++ b/SpringDateTime/pom.xml @@ -0,0 +1,159 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-date-time + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.3.5 + 5.4.28.Final + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + + + org.springframework + spring-orm + ${spring.version} + + + + + org.springframework.data + spring-data-jpa + 2.4.7 + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/SpringDateTime/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/SpringDateTime/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..dba65f7d --- /dev/null +++ b/SpringDateTime/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,54 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.CharacterEncodingFilter; +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.DispatcherType; +import javax.servlet.FilterRegistration; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import java.util.EnumSet; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerCharacterEncodingFilter(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null, true, "/*"); + } + + private void registerCharacterEncodingFilter(ServletContext aContext) { + EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD); + + CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); + characterEncodingFilter.setEncoding("UTF-8"); + characterEncodingFilter.setForceEncoding(true); + + FilterRegistration.Dynamic characterEncoding = aContext.addFilter("characterEncoding", characterEncodingFilter); + characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*"); + } +} diff --git a/SpringDateTime/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/SpringDateTime/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..37986ef9 --- /dev/null +++ b/SpringDateTime/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,115 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; +import java.util.Properties; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@PropertySource("classpath:hibernate.properties") +@EnableTransactionManagement +@EnableJpaRepositories("ru.alishev.springcourse.repositories") +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + private final Environment env; + + @Autowired + public SpringConfig(ApplicationContext applicationContext, Environment env) { + this.applicationContext = applicationContext; + this.env = env; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + templateResolver.setCharacterEncoding("UTF-8"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + resolver.setCharacterEncoding("UTF-8"); + + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName(env.getRequiredProperty("hibernate.driver_class")); + dataSource.setUrl(env.getRequiredProperty("hibernate.connection.url")); + dataSource.setUsername(env.getRequiredProperty("hibernate.connection.username")); + dataSource.setPassword(env.getRequiredProperty("hibernate.connection.password")); + + return dataSource; + } + + private Properties hibernateProperties() { + Properties properties = new Properties(); + properties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect")); + properties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql")); + + return properties; + } + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource()); + em.setPackagesToScan("ru.alishev.springcourse.models"); + + final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + em.setJpaVendorAdapter(vendorAdapter); + em.setJpaProperties(hibernateProperties()); + + return em; + } + + @Bean + public PlatformTransactionManager transactionManager() { + JpaTransactionManager transactionManager = new JpaTransactionManager(); + transactionManager.setEntityManagerFactory(entityManagerFactory().getObject()); + + return transactionManager; + } +} diff --git a/SpringDateTime/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/SpringDateTime/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..867ba974 --- /dev/null +++ b/SpringDateTime/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.models.Person; +import ru.alishev.springcourse.services.PeopleService; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PeopleService peopleService; + + @Autowired + public PeopleController(PeopleService peopleService) { + this.peopleService = peopleService; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", peopleService.findAll()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", peopleService.findOne(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + peopleService.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", peopleService.findOne(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + peopleService.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + peopleService.delete(id); + return "redirect:/people"; + } +} diff --git a/SpringDateTime/src/main/java/ru/alishev/springcourse/models/Person.java b/SpringDateTime/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..5911b10e --- /dev/null +++ b/SpringDateTime/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,111 @@ +package ru.alishev.springcourse.models; + +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * @author Neil Alishev + */ +@Entity +@Table(name = "Person") +public class Person { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + @Column(name = "name") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + @Column(name = "age") + private int age; + + @Column(name = "email") + @NotEmpty(message = "Email should not be empty") + @Email + private String email; + + @Column(name = "date_of_birth") + @Temporal(TemporalType.DATE) + @DateTimeFormat(pattern = "dd/MM/yyyy") // дд/мм/гггг + private Date dateOfBirth; + + @Column(name = "created_at") + @Temporal(TemporalType.TIMESTAMP) + private Date createdAt; + + public Person() { + + } + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Date getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(Date dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/SpringDateTime/src/main/java/ru/alishev/springcourse/repositories/PeopleRepository.java b/SpringDateTime/src/main/java/ru/alishev/springcourse/repositories/PeopleRepository.java new file mode 100644 index 00000000..5f2cf5fa --- /dev/null +++ b/SpringDateTime/src/main/java/ru/alishev/springcourse/repositories/PeopleRepository.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.alishev.springcourse.models.Person; + +/** + * @author Neil Alishev + */ +@Repository +public interface PeopleRepository extends JpaRepository { + +} diff --git a/SpringDateTime/src/main/java/ru/alishev/springcourse/services/PeopleService.java b/SpringDateTime/src/main/java/ru/alishev/springcourse/services/PeopleService.java new file mode 100644 index 00000000..45d054cd --- /dev/null +++ b/SpringDateTime/src/main/java/ru/alishev/springcourse/services/PeopleService.java @@ -0,0 +1,53 @@ +package ru.alishev.springcourse.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.alishev.springcourse.models.Person; +import ru.alishev.springcourse.repositories.PeopleRepository; + +import java.util.Date; +import java.util.List; +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Service +@Transactional(readOnly = true) +public class PeopleService { + + private final PeopleRepository peopleRepository; + + @Autowired + public PeopleService(PeopleRepository peopleRepository) { + this.peopleRepository = peopleRepository; + } + + public List findAll() { + return peopleRepository.findAll(); + } + + public Person findOne(int id) { + Optional foundPerson = peopleRepository.findById(id); + return foundPerson.orElse(null); + } + + @Transactional + public void save(Person person) { + person.setCreatedAt(new Date()); + + peopleRepository.save(person); + } + + @Transactional + public void update(int id, Person updatedPerson) { + updatedPerson.setId(id); + peopleRepository.save(updatedPerson); + } + + @Transactional + public void delete(int id) { + peopleRepository.deleteById(id); + } +} diff --git a/SpringDateTime/src/main/resources/hibernate.properties b/SpringDateTime/src/main/resources/hibernate.properties new file mode 100644 index 00000000..69717fea --- /dev/null +++ b/SpringDateTime/src/main/resources/hibernate.properties @@ -0,0 +1,9 @@ +# Конфигурация источника данных (Data Source) +hibernate.driver_class=org.postgresql.Driver +hibernate.connection.url=jdbc:postgresql://localhost:5432/hibernate_demo_db +hibernate.connection.username=postgres +hibernate.connection.password=postgres + +# Конфигурация самого Hibernate +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +hibernate.show_sql=true \ No newline at end of file diff --git a/SpringDateTime/src/main/webapp/WEB-INF/views/people/edit.html b/SpringDateTime/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/SpringDateTime/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/SpringDateTime/src/main/webapp/WEB-INF/views/people/index.html b/SpringDateTime/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/SpringDateTime/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/SpringDateTime/src/main/webapp/WEB-INF/views/people/new.html b/SpringDateTime/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..eadf7f1a --- /dev/null +++ b/SpringDateTime/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,31 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ + +
Date of birth Error
+
+ +
+ + + \ No newline at end of file diff --git a/SpringDateTime/src/main/webapp/WEB-INF/views/people/show.html b/SpringDateTime/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/SpringDateTime/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/SpringHibernateApp/pom.xml b/SpringHibernateApp/pom.xml new file mode 100644 index 00000000..b64b8fb9 --- /dev/null +++ b/SpringHibernateApp/pom.xml @@ -0,0 +1,152 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-hibernate-app + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + 5.4.28.Final + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + + + org.springframework + spring-orm + ${spring.version} + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/SpringHibernateApp/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/SpringHibernateApp/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..dba65f7d --- /dev/null +++ b/SpringHibernateApp/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,54 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.CharacterEncodingFilter; +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.DispatcherType; +import javax.servlet.FilterRegistration; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import java.util.EnumSet; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerCharacterEncodingFilter(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null, true, "/*"); + } + + private void registerCharacterEncodingFilter(ServletContext aContext) { + EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD); + + CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); + characterEncodingFilter.setEncoding("UTF-8"); + characterEncodingFilter.setForceEncoding(true); + + FilterRegistration.Dynamic characterEncoding = aContext.addFilter("characterEncoding", characterEncodingFilter); + characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*"); + } +} diff --git a/SpringHibernateApp/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/SpringHibernateApp/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..2300d915 --- /dev/null +++ b/SpringHibernateApp/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,115 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.hibernate5.HibernateTransactionManager; +import org.springframework.orm.hibernate5.LocalSessionFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; +import java.util.Properties; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@PropertySource("classpath:hibernate.properties") +@EnableTransactionManagement +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + private final Environment env; + + @Autowired + public SpringConfig(ApplicationContext applicationContext, Environment env) { + this.applicationContext = applicationContext; + this.env = env; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + templateResolver.setCharacterEncoding("UTF-8"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + resolver.setCharacterEncoding("UTF-8"); + + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName(env.getRequiredProperty("hibernate.driver_class")); + dataSource.setUrl(env.getRequiredProperty("hibernate.connection.url")); + dataSource.setUsername(env.getRequiredProperty("hibernate.connection.username")); + dataSource.setPassword(env.getRequiredProperty("hibernate.connection.password")); + + return dataSource; + } + + // Используем Hibernate вместо JdbcTemplate +// @Bean +// public JdbcTemplate jdbcTemplate() { +// return new JdbcTemplate(dataSource()); +// } + + private Properties hibernateProperties() { + Properties properties = new Properties(); + properties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect")); + properties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql")); + + return properties; + } + + @Bean + public LocalSessionFactoryBean sessionFactory() { + LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); + sessionFactory.setDataSource(dataSource()); + sessionFactory.setPackagesToScan("ru.alishev.springcourse.models"); + sessionFactory.setHibernateProperties(hibernateProperties()); + + return sessionFactory; + } + + @Bean + public PlatformTransactionManager hibernateTransactionManager() { + HibernateTransactionManager transactionManager = new HibernateTransactionManager(); + transactionManager.setSessionFactory(sessionFactory().getObject()); + + return transactionManager; + } +} diff --git a/SpringHibernateApp/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/SpringHibernateApp/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/SpringHibernateApp/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/SpringHibernateApp/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/SpringHibernateApp/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..f12178a7 --- /dev/null +++ b/SpringHibernateApp/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,50 @@ +package ru.alishev.springcourse.dao; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import ru.alishev.springcourse.models.Person; + +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + + private final SessionFactory sessionFactory; + + @Autowired + public PersonDAO(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + @Transactional(readOnly = true) + public List index() { + Session session = sessionFactory.getCurrentSession(); + + List people = session.createQuery("select p from Person p", Person.class) + .getResultList(); + + return people; + } + + public Person show(int id) { + return null; + } + + public void save(Person person) { + + } + + public void update(int id, Person updatedPerson) { + + } + + public void delete(int id) { + + } +} diff --git a/SpringHibernateApp/src/main/java/ru/alishev/springcourse/models/Person.java b/SpringHibernateApp/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..f8e20790 --- /dev/null +++ b/SpringHibernateApp/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,69 @@ +package ru.alishev.springcourse.models; + +import javax.persistence.*; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +@Entity +@Table(name = "Person") +public class Person { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + @Column(name = "name") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + @Column(name = "age") + private int age; + + public Person() { + + } + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/SpringHibernateApp/src/main/resources/hibernate.properties b/SpringHibernateApp/src/main/resources/hibernate.properties new file mode 100644 index 00000000..69717fea --- /dev/null +++ b/SpringHibernateApp/src/main/resources/hibernate.properties @@ -0,0 +1,9 @@ +# Конфигурация источника данных (Data Source) +hibernate.driver_class=org.postgresql.Driver +hibernate.connection.url=jdbc:postgresql://localhost:5432/hibernate_demo_db +hibernate.connection.username=postgres +hibernate.connection.password=postgres + +# Конфигурация самого Hibernate +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +hibernate.show_sql=true \ No newline at end of file diff --git a/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/edit.html b/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/index.html b/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/new.html b/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/show.html b/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/SpringHibernateApp/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/SpringHibernateCRUDApp/pom.xml b/SpringHibernateCRUDApp/pom.xml new file mode 100644 index 00000000..b57a9d70 --- /dev/null +++ b/SpringHibernateCRUDApp/pom.xml @@ -0,0 +1,152 @@ + + + + 4.0.0 + + ru.alishev.springcourse + spring-hibernate-crud-app + 1.0-SNAPSHOT + war + + spring-mvc-app1 Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + 5.2.1.RELEASE + 5.4.28.Final + + + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + + + org.springframework + spring-jdbc + ${spring.version} + + + + org.thymeleaf + thymeleaf-spring5 + 3.0.11.RELEASE + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.hibernate.validator + hibernate-validator + 6.1.6.Final + + + + + org.postgresql + postgresql + 42.2.18 + + + + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + + + org.springframework + spring-orm + ${spring.version} + + + + + spring-mvc-app1 + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java b/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java new file mode 100644 index 00000000..dba65f7d --- /dev/null +++ b/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/config/MySpringMvcDispatcherSerlvetIntitializer.java @@ -0,0 +1,54 @@ +package ru.alishev.springcourse.config; + +import org.springframework.web.filter.CharacterEncodingFilter; +import org.springframework.web.filter.HiddenHttpMethodFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +import javax.servlet.DispatcherType; +import javax.servlet.FilterRegistration; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import java.util.EnumSet; + +/** + * @author Neil Alishev + */ +public class MySpringMvcDispatcherSerlvetIntitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[]{SpringConfig.class}; + } + + @Override + protected String[] getServletMappings() { + return new String[]{"/"}; + } + + @Override + public void onStartup(ServletContext aServletContext) throws ServletException { + super.onStartup(aServletContext); + registerCharacterEncodingFilter(aServletContext); + registerHiddenFieldFilter(aServletContext); + } + + private void registerHiddenFieldFilter(ServletContext aContext) { + aContext.addFilter("hiddenHttpMethodFilter", + new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null, true, "/*"); + } + + private void registerCharacterEncodingFilter(ServletContext aContext) { + EnumSet dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD); + + CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); + characterEncodingFilter.setEncoding("UTF-8"); + characterEncodingFilter.setForceEncoding(true); + + FilterRegistration.Dynamic characterEncoding = aContext.addFilter("characterEncoding", characterEncodingFilter); + characterEncoding.addMappingForUrlPatterns(dispatcherTypes, true, "/*"); + } +} diff --git a/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/config/SpringConfig.java b/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/config/SpringConfig.java new file mode 100644 index 00000000..2300d915 --- /dev/null +++ b/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/config/SpringConfig.java @@ -0,0 +1,115 @@ +package ru.alishev.springcourse.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.hibernate5.HibernateTransactionManager; +import org.springframework.orm.hibernate5.LocalSessionFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; + +import javax.sql.DataSource; +import java.util.Properties; + +/** + * @author Neil Alishev + */ +@Configuration +@ComponentScan("ru.alishev.springcourse") +@PropertySource("classpath:hibernate.properties") +@EnableTransactionManagement +@EnableWebMvc +public class SpringConfig implements WebMvcConfigurer { + + private final ApplicationContext applicationContext; + + private final Environment env; + + @Autowired + public SpringConfig(ApplicationContext applicationContext, Environment env) { + this.applicationContext = applicationContext; + this.env = env; + } + + @Bean + public SpringResourceTemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setApplicationContext(applicationContext); + templateResolver.setPrefix("/WEB-INF/views/"); + templateResolver.setSuffix(".html"); + templateResolver.setCharacterEncoding("UTF-8"); + return templateResolver; + } + + @Bean + public SpringTemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + templateEngine.setEnableSpringELCompiler(true); + return templateEngine; + } + + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(templateEngine()); + resolver.setCharacterEncoding("UTF-8"); + + registry.viewResolver(resolver); + } + + @Bean + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName(env.getRequiredProperty("hibernate.driver_class")); + dataSource.setUrl(env.getRequiredProperty("hibernate.connection.url")); + dataSource.setUsername(env.getRequiredProperty("hibernate.connection.username")); + dataSource.setPassword(env.getRequiredProperty("hibernate.connection.password")); + + return dataSource; + } + + // Используем Hibernate вместо JdbcTemplate +// @Bean +// public JdbcTemplate jdbcTemplate() { +// return new JdbcTemplate(dataSource()); +// } + + private Properties hibernateProperties() { + Properties properties = new Properties(); + properties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect")); + properties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql")); + + return properties; + } + + @Bean + public LocalSessionFactoryBean sessionFactory() { + LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); + sessionFactory.setDataSource(dataSource()); + sessionFactory.setPackagesToScan("ru.alishev.springcourse.models"); + sessionFactory.setHibernateProperties(hibernateProperties()); + + return sessionFactory; + } + + @Bean + public PlatformTransactionManager hibernateTransactionManager() { + HibernateTransactionManager transactionManager = new HibernateTransactionManager(); + transactionManager.setSessionFactory(sessionFactory().getObject()); + + return transactionManager; + } +} diff --git a/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java b/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java new file mode 100644 index 00000000..8de8ccd7 --- /dev/null +++ b/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/controllers/PeopleController.java @@ -0,0 +1,75 @@ +package ru.alishev.springcourse.controllers; + +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.*; +import ru.alishev.springcourse.dao.PersonDAO; +import ru.alishev.springcourse.models.Person; + +import javax.validation.Valid; + +/** + * @author Neil Alishev + */ +@Controller +@RequestMapping("/people") +public class PeopleController { + + private final PersonDAO personDAO; + + @Autowired + public PeopleController(PersonDAO personDAO) { + this.personDAO = personDAO; + } + + @GetMapping() + public String index(Model model) { + model.addAttribute("people", personDAO.index()); + return "people/index"; + } + + @GetMapping("/{id}") + public String show(@PathVariable("id") int id, Model model) { + model.addAttribute("person", personDAO.show(id)); + return "people/show"; + } + + @GetMapping("/new") + public String newPerson(@ModelAttribute("person") Person person) { + return "people/new"; + } + + @PostMapping() + public String create(@ModelAttribute("person") @Valid Person person, + BindingResult bindingResult) { + if (bindingResult.hasErrors()) + return "people/new"; + + personDAO.save(person); + return "redirect:/people"; + } + + @GetMapping("/{id}/edit") + public String edit(Model model, @PathVariable("id") int id) { + model.addAttribute("person", personDAO.show(id)); + return "people/edit"; + } + + @PatchMapping("/{id}") + public String update(@ModelAttribute("person") @Valid Person person, BindingResult bindingResult, + @PathVariable("id") int id) { + if (bindingResult.hasErrors()) + return "people/edit"; + + personDAO.update(id, person); + return "redirect:/people"; + } + + @DeleteMapping("/{id}") + public String delete(@PathVariable("id") int id) { + personDAO.delete(id); + return "redirect:/people"; + } +} diff --git a/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java b/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java new file mode 100644 index 00000000..a2df23e3 --- /dev/null +++ b/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/dao/PersonDAO.java @@ -0,0 +1,60 @@ +package ru.alishev.springcourse.dao; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import ru.alishev.springcourse.models.Person; + +import java.util.List; + +/** + * @author Neil Alishev + */ +@Component +public class PersonDAO { + + private final SessionFactory sessionFactory; + + @Autowired + public PersonDAO(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + @Transactional(readOnly = true) + public List index() { + Session session = sessionFactory.getCurrentSession(); + + return session.createQuery("select p from Person p", Person.class) + .getResultList(); + } + + @Transactional(readOnly = true) + public Person show(int id) { + Session session = sessionFactory.getCurrentSession(); + return session.get(Person.class, id); + } + + @Transactional + public void save(Person person) { + Session session = sessionFactory.getCurrentSession(); + session.save(person); + } + + @Transactional + public void update(int id, Person updatedPerson) { + Session session = sessionFactory.getCurrentSession(); + Person personToBeUpdated = session.get(Person.class, id); + + personToBeUpdated.setName(updatedPerson.getName()); + personToBeUpdated.setAge(updatedPerson.getAge()); + personToBeUpdated.setEmail(updatedPerson.getEmail()); + } + + @Transactional + public void delete(int id) { + Session session = sessionFactory.getCurrentSession(); + session.remove(session.get(Person.class, id)); + } +} diff --git a/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/models/Person.java b/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/models/Person.java new file mode 100644 index 00000000..beddd581 --- /dev/null +++ b/SpringHibernateCRUDApp/src/main/java/ru/alishev/springcourse/models/Person.java @@ -0,0 +1,83 @@ +package ru.alishev.springcourse.models; + +import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +@Entity +@Table(name = "Person") +public class Person { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @NotEmpty(message = "Name should not be empty") + @Size(min = 2, max = 30, message = "Name should be between 2 and 30 characters") + @Column(name = "name") + private String name; + + @Min(value = 0, message = "Age should be greater than 0") + @Column(name = "age") + private int age; + + @Column(name = "email") + @NotEmpty(message = "Email should not be empty") + @Email + private String email; + + public Person() { + + } + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/SpringHibernateCRUDApp/src/main/resources/hibernate.properties b/SpringHibernateCRUDApp/src/main/resources/hibernate.properties new file mode 100644 index 00000000..69717fea --- /dev/null +++ b/SpringHibernateCRUDApp/src/main/resources/hibernate.properties @@ -0,0 +1,9 @@ +# Конфигурация источника данных (Data Source) +hibernate.driver_class=org.postgresql.Driver +hibernate.connection.url=jdbc:postgresql://localhost:5432/hibernate_demo_db +hibernate.connection.username=postgres +hibernate.connection.password=postgres + +# Конфигурация самого Hibernate +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +hibernate.show_sql=true \ No newline at end of file diff --git a/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/edit.html b/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/edit.html new file mode 100644 index 00000000..ba6aaaab --- /dev/null +++ b/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/edit.html @@ -0,0 +1,26 @@ + + + + + Update person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/index.html b/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/index.html new file mode 100644 index 00000000..f143f770 --- /dev/null +++ b/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/index.html @@ -0,0 +1,20 @@ + + + + + Index + + + +
+ user +
+ +
+
+ +Create new person + + + \ No newline at end of file diff --git a/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/new.html b/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/new.html new file mode 100644 index 00000000..3e2cc5c9 --- /dev/null +++ b/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/new.html @@ -0,0 +1,26 @@ + + + + + New person + + + +
+ + +
Name Error
+
+ + +
Age Error
+
+ + +
Email Error
+
+ +
+ + + \ No newline at end of file diff --git a/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/show.html b/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/show.html new file mode 100644 index 00000000..db8fb792 --- /dev/null +++ b/SpringHibernateCRUDApp/src/main/webapp/WEB-INF/views/people/show.html @@ -0,0 +1,18 @@ + + + + + Show + + +

VALUE

+

VALUE

+

VALUE

+ +Edit + +
+ +
+ + \ No newline at end of file diff --git a/UserDetailsServiceApp/.gitignore b/UserDetailsServiceApp/.gitignore new file mode 100644 index 00000000..549e00a2 --- /dev/null +++ b/UserDetailsServiceApp/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/UserDetailsServiceApp/.mvn/wrapper/MavenWrapperDownloader.java b/UserDetailsServiceApp/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 00000000..e76d1f32 --- /dev/null +++ b/UserDetailsServiceApp/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/UserDetailsServiceApp/.mvn/wrapper/maven-wrapper.jar b/UserDetailsServiceApp/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 00000000..2cc7d4a5 Binary files /dev/null and b/UserDetailsServiceApp/.mvn/wrapper/maven-wrapper.jar differ diff --git a/UserDetailsServiceApp/.mvn/wrapper/maven-wrapper.properties b/UserDetailsServiceApp/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..ffdc10e5 --- /dev/null +++ b/UserDetailsServiceApp/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/UserDetailsServiceApp/mvnw b/UserDetailsServiceApp/mvnw new file mode 100755 index 00000000..a16b5431 --- /dev/null +++ b/UserDetailsServiceApp/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/UserDetailsServiceApp/mvnw.cmd b/UserDetailsServiceApp/mvnw.cmd new file mode 100644 index 00000000..c8d43372 --- /dev/null +++ b/UserDetailsServiceApp/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/UserDetailsServiceApp/pom.xml b/UserDetailsServiceApp/pom.xml new file mode 100644 index 00000000..a6f56d93 --- /dev/null +++ b/UserDetailsServiceApp/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.1 + + + ru.alishev.springcourse + FirstSecurityApp + 0.0.1-SNAPSHOT + FirstSecurityApp + First Spring Boot app with Spring Security + + 11 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-web + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity5 + + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/UserDetailsServiceApplication.java b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/UserDetailsServiceApplication.java new file mode 100644 index 00000000..b63c77c6 --- /dev/null +++ b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/UserDetailsServiceApplication.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.FirstSecurityApp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class UserDetailsServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(UserDetailsServiceApplication.class, args); + } + +} diff --git a/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java new file mode 100644 index 00000000..0815774e --- /dev/null +++ b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/config/SecurityConfig.java @@ -0,0 +1,34 @@ +package ru.alishev.springcourse.FirstSecurityApp.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import ru.alishev.springcourse.FirstSecurityApp.services.PersonDetailsService; + +/** + * @author Neil Alishev + */ +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + private final PersonDetailsService personDetailsService; + + @Autowired + public SecurityConfig(PersonDetailsService personDetailsService) { + this.personDetailsService = personDetailsService; + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(personDetailsService); + } + + @Bean + public PasswordEncoder getPasswordEncoder() { + return NoOpPasswordEncoder.getInstance(); + } +} diff --git a/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java new file mode 100644 index 00000000..c0432fb9 --- /dev/null +++ b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/controllers/HelloController.java @@ -0,0 +1,27 @@ +package ru.alishev.springcourse.FirstSecurityApp.controllers; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import ru.alishev.springcourse.FirstSecurityApp.security.PersonDetails; + +/** + * @author Neil Alishev + */ +@Controller +public class HelloController { + @GetMapping("/hello") + public String sayHello() { + return "hello"; + } + + @GetMapping("/showUserInfo") + public String showUserInfo() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + PersonDetails personDetails = (PersonDetails) authentication.getPrincipal(); + System.out.println(personDetails.getPerson()); + + return "hello"; + } +} diff --git a/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java new file mode 100644 index 00000000..b084d0c4 --- /dev/null +++ b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/models/Person.java @@ -0,0 +1,81 @@ +package ru.alishev.springcourse.FirstSecurityApp.models; + +import javax.persistence.*; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +/** + * @author Neil Alishev + */ +@Entity +@Table(name = "Person") +public class Person { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @NotEmpty(message = "Имя не должно быть пустым") + @Size(min = 2, max = 100, message = "Имя должно быть от 2 до 100 символов длиной") + @Column(name = "username") + private String username; + + @Min(value = 1900, message = "Год рождения должен быть больше, чем 1900") + @Column(name = "year_of_birth") + private int yearOfBirth; + + @Column(name = "password") + private String password; + + // Конструктор по умолчанию нужен для Spring + public Person() { + } + + public Person(String username, int yearOfBirth) { + this.username = username; + this.yearOfBirth = yearOfBirth; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public int getYearOfBirth() { + return yearOfBirth; + } + + public void setYearOfBirth(int yearOfBirth) { + this.yearOfBirth = yearOfBirth; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", username='" + username + '\'' + + ", yearOfBirth=" + yearOfBirth + + ", password='" + password + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java new file mode 100644 index 00000000..569af7a4 --- /dev/null +++ b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/repositories/PeopleRepository.java @@ -0,0 +1,15 @@ +package ru.alishev.springcourse.FirstSecurityApp.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; + +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Repository +public interface PeopleRepository extends JpaRepository { + Optional findByUsername(String username); +} diff --git a/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java new file mode 100644 index 00000000..0c58f086 --- /dev/null +++ b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/security/PersonDetails.java @@ -0,0 +1,58 @@ +package ru.alishev.springcourse.FirstSecurityApp.security; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; + +import java.util.Collection; + +/** + * @author Neil Alishev + */ +public class PersonDetails implements UserDetails { + private final Person person; + + public PersonDetails(Person person) { + this.person = person; + } + + @Override + public Collection getAuthorities() { + return null; + } + + @Override + public String getPassword() { + return this.person.getPassword(); + } + + @Override + public String getUsername() { + return this.person.getUsername(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + // Нужно, чтобы получать данные аутентифицированного пользователя + public Person getPerson() { + return this.person; + } +} diff --git a/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java new file mode 100644 index 00000000..4ca5432a --- /dev/null +++ b/UserDetailsServiceApp/src/main/java/ru/alishev/springcourse/FirstSecurityApp/services/PersonDetailsService.java @@ -0,0 +1,36 @@ +package ru.alishev.springcourse.FirstSecurityApp.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import ru.alishev.springcourse.FirstSecurityApp.models.Person; +import ru.alishev.springcourse.FirstSecurityApp.repositories.PeopleRepository; +import ru.alishev.springcourse.FirstSecurityApp.security.PersonDetails; + +import java.util.Optional; + +/** + * @author Neil Alishev + */ +@Service +public class PersonDetailsService implements UserDetailsService { + + private final PeopleRepository peopleRepository; + + @Autowired + public PersonDetailsService(PeopleRepository peopleRepository) { + this.peopleRepository = peopleRepository; + } + + @Override + public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { + Optional person = peopleRepository.findByUsername(s); + + if (person.isEmpty()) + throw new UsernameNotFoundException("User not found"); + + return new PersonDetails(person.get()); + } +} diff --git a/UserDetailsServiceApp/src/main/resources/application.properties b/UserDetailsServiceApp/src/main/resources/application.properties new file mode 100644 index 00000000..ffd7c456 --- /dev/null +++ b/UserDetailsServiceApp/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/security_app_db +spring.datasource.username=postgres +spring.datasource.password=postgres + +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.show_sql=true \ No newline at end of file diff --git a/UserDetailsServiceApp/src/main/resources/templates/hello.html b/UserDetailsServiceApp/src/main/resources/templates/hello.html new file mode 100644 index 00000000..da114098 --- /dev/null +++ b/UserDetailsServiceApp/src/main/resources/templates/hello.html @@ -0,0 +1,10 @@ + + + + + Hello + + +Hello world! + + \ No newline at end of file diff --git a/UserDetailsServiceApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/UserDetailsServiceApplicationTests.java b/UserDetailsServiceApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/UserDetailsServiceApplicationTests.java new file mode 100644 index 00000000..03c9cc0a --- /dev/null +++ b/UserDetailsServiceApp/src/test/java/ru/alishev/springcourse/FirstSecurityApp/UserDetailsServiceApplicationTests.java @@ -0,0 +1,13 @@ +package ru.alishev.springcourse.FirstSecurityApp; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class UserDetailsServiceApplicationTests { + + @Test + void contextLoads() { + } + +}