IoC рд╕реНрдЯрд╛рд░реНрдЯрд░ рдХреЗ рд╕рд╛рде рд╡реЗрдм рдРрдкред Ioc рд╕рдВрджрд░реНрдн, ioc рд╡реЗрдм рдФрд░ ioc orm рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдореВрд▓ рдХреНрд╡реЗрд░реА рдореИрдкрд┐рдВрдЧ

рдЫрд╡рд┐

рдкрд░рд┐рдЪрдп


рдкрд╣рд▓реА рд░рд┐рд▓реАрдЬ рдХреЗ рдмрд╛рдж рд╕реЗ, рдмрд╣реБрдд рд╕рдордп рдмреАрдд рдЪреБрдХрд╛ рд╣реИ ( рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦ рдХреЗ рд▓рд┐рдП рд▓рд┐рдВрдХ )ред рдХреНрдпрд╛ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ?


  • рдПрдХ рдкреВрд░реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рдгрд╛рд▓реА рдХреА рдмреЗрд╣рддрд░ рд╕реНрдерд┐рд░рддрд╛;
  • рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдЖрд▓рд╕реА рдШрдЯрдХ рд▓реЛрдб рд╣реЛ рд░рд╣рд╛ рд╣реИ;
  • рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдмреБрдирд┐рдпрд╛рджреА рд╢реНрд░реЛрддрд╛ рдкреНрд░рдгрд╛рд▓реА
  • рдкрд╣рд▓реВ-рдЙрдиреНрдореБрдЦ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рд╕рдорд░реНрдерди (рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдореЗрдВ рдордзреНрдпрдо рдХрдард┐рдирд╛рдИ рдХреЗ рд▓рд┐рдП, рдЕрдиреНрдпрдерд╛ рдореИрдВ рдЖрдкрдХреЛ рдмрд╛рдХреА рдХреЗ рд▓рд┐рдП рдПрд╕реНрдкреЗрдХреНрдЯрдЬ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВ)
  • рдирдпрд╛ рд░рд┐рдХреНрдлрд╝рд░реНрд╡реЗрдЯрд░реА рдмреВрдЯ рд▓реЛрдбрд░
  • EhCache, рдЕрдорд░реВрдж рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдХреИрд╢ рдХреЗ рд╕рд╛рде рдПрдХреАрдХреГрдд рдХрд╛рд░реНрдп
  • рдзрд╛рд░рд╛рдУрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдПрдХреАрдХреГрдд рд╣реИ (@SimpleTask рдПрдиреЛрдЯреЗрд╢рди рдФрд░ рдкреВрд▓ рдХреЗ рд╕рд╛рде рд╕реАрдзреЗ рдХрд╛рдо рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рджреЛрдиреЛрдВ рдЖрд░рдВрднреАрдХрд░рдг)

** рдореЙрдбреНрдпреВрд▓


  • рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЙрдбреНрдпреВрд▓ (рдЬреЗрдкреАрдП, рд▓реЗрдирджреЗрди рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдХреЗ рд╕рд╛рде рд╣рд▓реНрдХреЗ рдУрдЖрд░рдПрдо, рдиреЛ-рдПрд╕рдХреНрдпреВрдПрд▓ рдбреНрд░рд╛рдЗрд╡рд░ - рдУрд░рд┐рдПрдВрдЯ, рдХреНрд░реВрдб рд╡рд┐рдзрд┐рдпреЛрдВ, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕рд┐рд╕реНрдЯрдо рдФрд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреНрд▓рд╛рд╕ рдХреЗ рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдСрдЯреЛ-рдЬрдирд░реЗрдЯ рдХрд┐рдП рдЧрдП рдкреНрд░рд╢реНрди)
  • рд╡реЗрдм рдереВрдерди рдореЙрдбреНрдпреВрд▓ (рд▓рд┐рдВрдХ рдорд╛рдирдЪрд┐рддреНрд░рдг рдПрдиреЛрдЯреЗрд╢рди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ, рдХрд╕реНрдЯрдо рдЙрддреНрдкрд╛рджрдХреЛрдВ / рдЙрдкрднреЛрдЧрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди, рд╡реЗрд▓рдХрдо рдЯреЗрдореНрдкреНрд▓реЗрдЯ рд░реЗрдВрдбрд░рд┐рдВрдЧ рдкреЗрдЬ, рдмреЗрд╕рд┐рдХ рд╕рд┐рдХреНрдпреЛрд░рд┐рдЯреА рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ, рд╕реЗрд╢рдВрд╕, рдХреБрдХреАрдЬ, рдПрд╕рдПрд╕рдПрд▓) рдиреЗрдЯреНрдЯреА 4.1.30 рдкрд░ рдЖрдзрд╛рд░рд┐рддред

рдврд╛рдВрдЪрд╛ рд╕рдВрд░рдЪрдирд╛
struct


"рдмреЗрд╢рдХ, рдпрд╣ рд╕рдм рдЕрдЪреНрдЫрд╛ рд╣реИ," рдЖрдк рдХрд╣рддреЗ рд╣реИрдВ, "рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рд╕рдм рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ?"
"рд╣рд╛рдБ, рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдореИрдВ рдХрдЯреМрддреА рдХреЗ рд▓рд┐рдП рдХрд╣рддрд╛ рд╣реВрдВред"


рдЙрджрд╛рд╣рд░рдг рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкреНрд░рдХреНрд░рд┐рдпрд╛


рдЙрджрд╛рд╣рд░рдг рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдорд╛рд╡реЗрди 3 рдФрд░ рдЗрдВрдЯреЗрд▓реАрдЬ рдЖрдЗрдбрд┐рдпрд╛ 2018.2 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛ред


1) рдирд┐рд░реНрднрд░рддрд╛ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВ:


<?xml version="1.0" encoding="UTF-8"?> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>example-webapp</artifactId> <groupId>org.ioc</groupId> <packaging>jar</packaging> <version>0.0.1</version> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <.source>1.8</source> <target>1.8</target> </configuration> <executions> <execution> <id>default-testCompile</id> <phase>test-compile</phase> <goals> <goal>testCompile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.ioc</groupId> <artifactId>context-factory</artifactId> <version>2.2.4.STABLE</version> </dependency> <dependency> <groupId>org.ioc</groupId> <artifactId>orm-factory</artifactId> <version>2.2.4.STABLE</version> </dependency> <dependency> <groupId>org.ioc</groupId> <artifactId>web-factory</artifactId> <version>2.2.4.STABLE</version> </dependency> </dependencies> <repositories> <repository> <id>context</id> <url>https://raw.github.com/GenCloud/ioc_container/context</url> </repository> <repository> <id>cache</id> <url>https://raw.github.com/GenCloud/ioc_container/cache</url> </repository> <repository> <id>threading</id> <url>https://raw.github.com/GenCloud/ioc_container/threading</url> </repository> <repository> <id>orm</id> <url>https://raw.github.com/GenCloud/ioc_container/orm</url> </repository> <repository> <id>web</id> <url>https://raw.github.com/GenCloud/ioc_container/web</url> </repository> </repositories> </project> 

** рд╡рд╣ рдЕрднреА рддрдХ рдХреЗрдВрджреНрд░реАрдп, рдЕрдлрд╕реЛрд╕ рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдирд╣реАрдВ рд╣реБрдЖ рд╣реИред


рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╕рдВрд░рдЪрдирд╛:
рд╕рдВрд░рдЪрдирд╛
рдорд╛рдирдХ MVC рдкреИрдЯрд░реНрди, рд╣реИ рдирд╛?


рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рд╡реЗрд╢ рдмрд┐рдВрджреБ рдмрдирд╛рдПрдБ:


 package org.examples.webapp; import org.ioc.annotations.context.ScanPackage; import org.ioc.annotations.modules.CacheModule; import org.ioc.annotations.modules.DatabaseModule; import org.ioc.annotations.modules.ThreadingModule; import org.ioc.annotations.modules.WebModule; import org.ioc.context.starter.IoCStarter; @WebModule @CacheModule @ThreadingModule @DatabaseModule @ScanPackage(packages = {"org.examples.webapp"}) public class AppMain { public static void main(String[] args) { IoCStarter.start(AppMain.class); } } 

** рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг:
рдПрдиреЛрдЯреЗрд╢рди @ScanPackages - рдШрдЯрдХреЛрдВ рдХреА рдкрд╣рдЪрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдкреИрдХреЗрдЬ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ (рдЖрдо рд▓реЛрдЧреЛрдВ рдореЗрдВ - "рдбрд┐рдмреНрдмреЗ")ред
рдПрдиреЛрдЯреЗрд╢рди @WebModule - рд╡реЗрдм рдлреИрдХреНрдЯреНрд░реА рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдФрд░ рдЖрд░рдВрдн рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред
рдПрдиреЛрдЯреЗрд╢рди @CacheModule - ORM рдХреЗ рд╕рд╣реА рд╕рдВрдЪрд╛рд▓рди рдХреЗ рд▓рд┐рдП (рднрд╡рд┐рд╖реНрдп рдХреЗ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдореЗрдВ, рдПрдиреЛрдЯреЗрд╢рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрдЧреА), рдХреИрд╢ рдлреИрдХреНрдЯреНрд░реА рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдФрд░ рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдПрдиреЛрдЯреЗрд╢рди @ThreadingModule - рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рд╕реА рдереНрд░реЗрдб рдлреИрдХреНрдЯреНрд░реА рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдФрд░ рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╡реЗрдм рдлреИрдХреНрдЯреНрд░реА рдХреЗ рд╕рд╣реА рд╕рдВрдЪрд╛рд▓рди рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рднрд╡рд┐рд╖реНрдп рдХреЗ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдореЗрдВ, рдПрдиреЛрдЯреЗрд╢рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрдЧреА)ред
рдПрдиреЛрдЯреЗрд╢рди @DatabaseModule - ORM рдлреИрдХреНрдЯреНрд░реА рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдФрд░ рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рдпреБрдХреНрдд ред
рд╕рднреА рдХрд╛рд░рдЦрд╛рдиреЛрдВ рдореЗрдВ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╡рд┐рдиреНрдпрд╛рд╕рдХрд░реНрддрд╛ рд╣реЛрддреЗ рд╣реИрдВ, рдЬрд┐рдиреНрд╣реЗрдВ рдЖрдк рдХрд╛рд░рдЦрд╛рдиреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдХреЗ рд╕рд╛рде рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ (рдкреНрд░рддреНрдпреЗрдХ рдореЙрдбреНрдпреВрд▓ рдПрдиреЛрдЯреЗрд╢рди рдореЗрдВ рд╡рд░реНрдЧ рд╡рд┐рдиреНрдпрд╛рд╕рдХрд░реНрддрд╛ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ - рдХрдХреНрд╖рд╛ <?> AutoConfigurationClass () default WebAutoConfiguration.class ), рдпрд╛ @Exclude annotlude рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рд╕реА рднреА рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдЕрдХреНрд╖рдо рдХрд░реЗрдВ ? рд╡рд░реНрдЧред
IoCStarter рдХреА рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдореБрдЦреНрдп рд╕рдВрджрд░реНрдн рдЖрд░рдореНрднрд┐рдХ рд╡рд░реНрдЧ рд╣реИред


рдареАрдХ рд╣реИ, рд╕рдм рдХреБрдЫ рддреИрдпрд╛рд░ рд▓рдЧрддрд╛ рд╣реИ, рд╕рдВрджрд░реНрдн рдЖрд░рдВрднрд┐рдХ рд╣реИ, рд╡реЗрдм рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкреЛрд░реНрдЯ 8081 рдкрд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХреЛрдИ рд▓рд┐рдВрдХ рдирд╣реАрдВ рд╣реИ, рдФрд░ рдЬрдм рд╣рдо рд╕рд╛рдЗрдЯ рдкрд░ рдЬрд╛рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╣рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред рдЦреИрд░, рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВред


рдЖрдЗрдП рд╣рдорд╛рд░реЗ рдореЙрдбреНрдпреВрд▓ рдХреЗ рд▓рд┐рдП рдПрдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдВред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рд╕рднреА рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди {working_dir} /configs/default_settings.properties рд╕реЗ рд▓реЛрдб рдХрд┐рдП рдЧрдП рд╣реИрдВ - рд╣рдо рдЗрд╕реЗ рдЙрдкрдпреБрдХреНрдд рдкрде рдХреЗ рд╕рд╛рде рдмрдирд╛рдПрдВрдЧреЗред


 # Threading ioc.threads.poolName=shared ioc.threads.availableProcessors=4 ioc.threads.threadTimeout=0 ioc.threads.threadAllowCoreTimeOut=true ioc.threads.threadPoolPriority=NORMAL # Event dispather # -  ()    ( ) ioc.dispatcher.availableDescriptors=4 # Cache #   (EhFactory|GuavaFactory) cache.factory=org.ioc.cache.impl.EhFactory # Datasource #   (-, -  ) #LOCAL, LOCAL_SERVER, REMOTE datasource.orient.database-type=LOCAL #   datasource.orient.url=./database #    (   ) datasource.orient.database=orient #   datasource.orient.username=admin #   datasource.orient.password=admin #       (create, dropCreate, refresh, none) datasource.orient.ddl-auto=dropCreate #   ,      datasource.orient.showSql=true # Web server #     web.server.port=8081 #   SSL  web.server.ssl-enabled=false # in seconds #   ( 7200 . = 2 ) web.server.security.session.timeout=300 #  - web.server.velocity.input.encoding=UTF-8 web.server.velocity.output.encoding=UTF-8 #  - web.server.velocity.resource.loader=file #   web.server.velocity.resource.loader.class=org.apache.velocity.runtime.resource.loader.FileResourceLoader #    - web.server.velocity.resource.loading.path=./public 

рдЕрдЧрд▓рд╛, рд╣рдореЗрдВ рдПрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдХрд╛рдИ рдФрд░ рдЙрд╕рдХреЗ рдкреНрд░рдмрдВрдзрди рднрдВрдбрд╛рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
TblAccount рдЗрдХрд╛рдИ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди:


 package org.examples.webapp.domain.entity; import org.ioc.web.security.user.UserDetails; import javax.persistence.*; import java.util.Collections; import java.util.List; @Entity public class TblAccount implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private long id; @Column(name = "username") private String username; @Column(name = "password") private String password; @Transient private String repeatedPassword; public String getRepeatedPassword() { return repeatedPassword; } public void setRepeatedPassword(String repeatedPassword) { this.repeatedPassword = repeatedPassword; } @Override public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public List<String> getRoles() { return Collections.singletonList("ROLE_USER"); } } 

** рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг:
рд╕рднреА рдЬреЗрдкреАрдП-рд╕рдкреЛрд░реНрдЯрд┐рдВрдЧ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рд╕рд╛рде рд╕рдм рдХреБрдЫ рдорд╛рдирдХ рд╣реИред @ .Entity рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрдХрд╛рдИ рдХреЛ рдореИрдк рдХрд░реЗрдВ, @ .Id рдПрдиреЛрдЯреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдВрдЬреА рдмрдирд╛рдПрдВ, @ рдХреЙрд▓рдо рдПрдиреЛрдЯреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреЙрд▓рдо рдХреЛ рдореИрдк рдХрд░реЗрдВ ред рдФрд░ рд╕реБрд░рдХреНрд╖рд╛ рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рдЗрдХрд╛рдИ рдХреА рдкрд╣рдЪрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП UserDetails рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓рд╛ред


TblAccountRepository рдЗрдХрд╛рдИ рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди:


 package org.examples.webapp.domain.repository; import org.examples.webapp.domain.entity.TblAccount; import org.ioc.annotations.context.IoCRepository; import org.ioc.orm.repositories.CrudRepository; import javax.transaction.Transactional; @IoCRepository public interface TblAccountRepository extends CrudRepository<TblAccount, Long> { @Transactional TblAccount findByUsernameEq(String username); } 

** рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг:
рдПрдиреЛрдЯреЗрд╢рди @IoCRepository - рдЗрд╕ рд╕рдВрджрд░реНрдн рд╕реЗ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рд╡рд░реНрдЧ рдПрдХ рднрдВрдбрд╛рд░ рд╣реИ рдФрд░ рдЗрд╕реЗ "рдЕрд▓рдЧ рддрд░реАрдХреЗ" рд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдорд╛рдирдХ CRUD рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ:


  • Entity fetch (ID id) - рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ Entity рдХреА рдПрдХ рдЗрдХрд╛рдИ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рдпрд╛ рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдВрдЬреА рджреНрд╡рд╛рд░рд╛ рдХреИрд╢ рд╕реЗ;
  • рд╕реВрдЪреА fetchAll () - рдирд┐рдХрд╛рдп рдкреНрд░рдХрд╛рд░ рдХреА рд╕рднреА рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рдЙрдиреНрд╣реЗрдВ рдХреИрд╢ рдореЗрдВ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ;
  • рд╢реВрдиреНрдп рд╕реЗрд╡ (рдЗрдХрд╛рдИ рдЗрдХрд╛рдИ) - рдбреЗрдЯрд╛рдмреЗрд╕ рдФрд░ рдХреИрд╢ рдореЗрдВ рджреЛрдиреЛрдВ рдкреНрд░рдХрд╛рд░ рдХреА рдЗрдХрд╛рдИ рдХреА рдПрдХ рдЗрдХрд╛рдИ рдмрдирд╛рддрд╛ / рдЕрдкрдбреЗрдЯ рдХрд░рддрд╛ рд╣реИ;
  • рд╢реВрдиреНрдп рд╣рдЯрд╛рдирд╛ (рдЗрдХрд╛рдИ рдЗрдХрд╛рдИ) - рдбреЗрдЯрд╛рдмреЗрд╕ рдФрд░ рдХреИрд╢ рд╕реЗ рджреЛрдиреЛрдВ рдкреНрд░рдХрд╛рд░ рдХреА рдЗрдХрд╛рдИ рд╣рдЯрд╛рддрд╛ рд╣реИ;
  • рдмреВрд▓рд┐рдпрди рдореМрдЬреВрдж рд╣реИ (рдЖрдИрдбреА рдЖрдИрдбреА) - рдЪреЗрдХ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдХреЛрдИ рдЗрдХрд╛рдИ рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдВрдЬреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдореМрдЬреВрдж рд╣реИред
    рд╕рднреА CRUD рдЕрдиреБрд░реЛрдз рдПрдХ рд▓реЗрдирджреЗрди рдореЗрдВ рд╣реЛрддреЗ рд╣реИрдВред

рдпрд╣ рдЦреЛрдЬрд╢рдмреНрджреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдХреЗ рдСрдЯреЛ-рдЬреЗрдирд░реЗрд╢рди рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ рдКрдкрд░ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рд╣реИ ( TblAccount findByUsernameEq (рд╕реНрдЯреНрд░рд┐рдВрдЧ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо) ) рдФрд░ рдкрдВрдЬреАрдХреГрдд рдкреНрд░рд╢реНрдиреЛрдВ рдХреЛ рдХреЙрд▓ рдХрд░рдирд╛ ( NamedQuery )


рдлрд╝рдВрдХреНрд╢рди findByUsernameEq (рд╕реНрдЯреНрд░рд┐рдВрдЧ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо) - рдЗрд╕рдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо рдлрд╝реАрд▓реНрдб рджреНрд╡рд╛рд░рд╛ рдПрдХ рдЗрдХрд╛рдИ рдХреА рдЦреЛрдЬ рдХрд░рддрд╛ рд╣реИред рдЙрддреНрдкрдиреНрди рдЕрдиреБрд░реЛрдз:


  select * from tbl_account where username = 'username' 

рдЕрдЧрд▓рд╛, рд╣рдореЗрдВ рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рдХреЗ рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрддрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдЦрд╛рддрд╛ рд╕реЗрд╡рд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди:


 package org.examples.webapp.service; import org.examples.webapp.domain.entity.TblAccount; import org.examples.webapp.domain.repository.TblAccountRepository; import org.examples.webapp.responces.IMessage; import org.ioc.annotations.context.IoCComponent; import org.ioc.annotations.context.IoCDependency; import org.ioc.web.model.http.Request; import org.ioc.web.security.configuration.SecurityConfigureAdapter; import org.ioc.web.security.encoder.bcrypt.BCryptEncoder; import org.ioc.web.security.user.UserDetails; import org.ioc.web.security.user.UserDetailsProcessor; import java.util.Objects; import static org.examples.webapp.responces.IMessage.Type.ERROR; import static org.examples.webapp.responces.IMessage.Type.OK; @IoCComponent public class AccountService implements UserDetailsProcessor { @IoCDependency private TblAccountRepository tblAccountRepository; @IoCDependency private BCryptEncoder bCryptEncoder; @IoCDependency private SecurityConfigureAdapter securityConfigureAdapter; @Override public UserDetails loadUserByUsername(String username) { return tblAccountRepository.findByUsernameEq(username); } public void save(TblAccount tblAccount) { tblAccountRepository.save(tblAccount); } public void delete(TblAccount tblAccount) { tblAccountRepository.delete(tblAccount); } public IMessage tryCreateUser(String username, String password, String repeatedPassword) { if (username == null || username.isEmpty() || password == null || password.isEmpty() || repeatedPassword == null || repeatedPassword.isEmpty()) { return new IMessage(ERROR, "Invalid request parameters!"); } if (!Objects.equals(password, repeatedPassword)) { return new IMessage(ERROR, "Repeated password doesn't match!"); } final UserDetails userDetails = loadUserByUsername(username); if (userDetails != null) { return new IMessage(ERROR, "Account already exists!"); } final TblAccount account = new TblAccount(); account.setUsername(username); account.setPassword(bCryptEncoder.encode(password)); save(account); return new IMessage(OK, "Successfully created!"); } public IMessage tryAuthenticateUser(Request request, String username, String password) { if (username == null || username.isEmpty() || password == null || password.isEmpty()) { return new IMessage(ERROR, "Invalid request parameters!"); } final UserDetails userDetails = loadUserByUsername(username); if (userDetails == null) { return new IMessage(ERROR, "Account not found!"); } if (!bCryptEncoder.match(password, userDetails.getPassword())) { return new IMessage(ERROR, "Password does not match!"); } securityConfigureAdapter.getContext().authenticate(request, userDetails); return new IMessage(OK, "Successfully authenticated"); } public IMessage logout(Request request) { if (securityConfigureAdapter.getContext().removeAuthInformation(request)) { return new IMessage(OK, "/"); } return new IMessage(ERROR, "Credentials not found or not authenticated!"); } } 

** рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг:
рдПрдиреЛрдЯреЗрд╢рди @IoCComponent - рдПрдХ рдШрдЯрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╡рд░реНрдЧ рдХреЛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред
рдПрдиреЛрдЯреЗрд╢рди @IoCD рдирд┐рд░реНрднрд░рддрд╛ - рдПрдХ рд╡рд░реНрдЧ рдХреА рдЖрд╡реГрддреНрддрд┐ рдореЗрдВ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рдпреБрдХреНрдд ред
BCryptEncoder рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдкрд╛рд╕рд╡рд░реНрдб рдПрдиреНрдХреНрд░рд┐рдкреНрд╢рди (рдЕрдм рддрдХ рдХреЗрд╡рд▓ рдХреЛрдбреЗрдХ) рдХреЗ рд▓рд┐рдП BCrypt рдХреЛрдбреЗрдХ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИред
рд╕рд┐рд╕реНрдЯрдо рдЙрджрд╛рд╣рд░рдг SecurityConfigureAdapter - рдХрд╛ рдЙрдкрдпреЛрдЧ рдореИрдкрд┐рдВрдЧ рдЕрдиреБрд░реЛрдзреЛрдВ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕рддреНрд░ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
UserDetails loadUserByUsername - рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓рд╛ рдлрд╝рдВрдХреНрд╢рди UserDetailsProcessor , рд╕рддреНрд░ рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рд▓реЛрдб рдХрд░рдиреЗ рдФрд░ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдзреНрд╡рдЬ ( рд╕реБрд░рдХреНрд╖рд╛ рдореЗрдВ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреЗ рдорд╛рдирдХ рдорд╛рдирдЪрд┐рддреНрд░рдг рдХреЗ рд▓рд┐рдП рднрд╡рд┐рд╖реНрдп рдореЗрдВ) рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ
IMessage рдлрд╝рдВрдХреНрд╢рди tryCreateUser рдПрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд┐рд░реНрдорд╛рдг рдлрд╝рдВрдХреНрд╢рди рд╣реИред
IMessage function tryAuthenticateUser - рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдлрд╝рдВрдХреНрд╢рдиред
IMessage рд▓реЙрдЧрдЖрдЙрдЯ рдлрд╝рдВрдХреНрд╢рди рдПрдХ рдЕрдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕реЗ рдПрдХ рд╕рддреНрд░ рдХреЛ рд╕рд╛рдлрд╝ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИред
IMessage class рдмреНрд░рд╛рдЙрдЬрд╝рд░ (json response) рдореЗрдВ рд╣рдорд╛рд░реЗ рджреНрд╡рд╛рд░рд╛ рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╡рд░реНрдЧ рд╣реИред


 package org.examples.webapp.responces; public class IMessage { private final String message; private final Type type; public IMessage(String message) { this.message = message; type = Type.OK; } public IMessage(Type type, String message) { this.message = message; this.type = type; } public String getMessage() { return message; } public Type getType() { return type; } public enum Type { OK, ERROR } } 

рдЕрдм рдЖрдкрдХреЛ рд╕реНрд╡рдпрдВ рд▓рд┐рдВрдХ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдЕрдиреБрд░реЛрдз рдорд╛рдирдЪрд┐рддреНрд░рдг):


 package org.examples.webapp.mapping; import org.examples.webapp.domain.entity.TblAccount; import org.examples.webapp.responces.IMessage; import org.examples.webapp.service.AccountService; import org.ioc.annotations.context.IoCDependency; import org.ioc.annotations.web.IoCController; import org.ioc.web.annotations.Credentials; import org.ioc.web.annotations.MappingMethod; import org.ioc.web.annotations.RequestParam; import org.ioc.web.annotations.UrlMapping; import org.ioc.web.model.ModelAndView; import org.ioc.web.model.http.Request; @IoCController @UrlMapping("/") public class MainMapping { @IoCDependency private AccountService accountService; @UrlMapping public ModelAndView index() { final ModelAndView modelAndView = new ModelAndView(); modelAndView.setView("index"); return modelAndView; } @UrlMapping(value = "signup", method = MappingMethod.POST) public IMessage createUser(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("repeatedPassword") String repeatedPassword) { return accountService.tryCreateUser(username, password, repeatedPassword); } @UrlMapping(value = "signin", method = MappingMethod.POST) public IMessage auth(Request request, @RequestParam("username") String username, @RequestParam("password") String password) { return accountService.tryAuthenticateUser(request, username, password); } @UrlMapping("signout") public IMessage signout(Request request) { return accountService.logout(request); } @UrlMapping("loginPage") public ModelAndView authenticated(@Credentials TblAccount account) { final ModelAndView modelAndView = new ModelAndView(); modelAndView.setView("auth"); modelAndView.addAttribute("account", account); return modelAndView; } } 

** рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг:
рдПрдиреЛрдЯреЗрд╢рди @IoCController - рдПрдХ рдирд┐рдпрдВрддреНрд░рдХ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдВрджрд░реНрдн рдореЗрдВ рд╡рд░реНрдЧ рдХреА рдкрд╣рдЪрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ (рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЕрдиреБрд░реЛрдз рдореИрдкрд░)
рдПрдиреЛрдЯреЗрд╢рди @UrlMapping - рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЪреИрдирд▓ рд╕рдВрдЪрд╛рд▓рдХреЛрдВ рджреНрд╡рд╛рд░рд╛ рд╕рдВрд╕рд╛рдзрд┐рдд рдЕрдиреБрд░реЛрдзреЛрдВ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди / рд╡рд░реНрдЧ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред
рд╡рд┐рдХрд▓реНрдк:


  • рдореВрд▓реНрдп - рдЕрдиреБрд░реЛрдз рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдП;
  • рд╡рд┐рдзрд┐ - рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП http рд╡рд┐рдзрд┐ (GET, POST, PUT, рдЖрджрд┐);
  • рднрд╕реНрдо - HTTP рдорд╛рдЗрдо рдкреНрд░рдХрд╛рд░ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреНрд░рдХрд╛рд░ (рд╡реИрдХрд▓реНрдкрд┐рдХ) рдХреЗ рдЕрдиреБрд░реЛрдз рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП;
  • рдЙрддреНрдкрд╛рджрди - рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕рд╛рдордЧреНрд░реА рдкреНрд░рдХрд╛рд░ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП http рд╕рд╛рдордЧреНрд░реА-рдкреНрд░рдХрд╛рд░ (рд╕рд╛рдордЧреНрд░реА-рдкреНрд░рдХрд╛рд░: рдкрд╛рда / html; рдЪрд╛рд░рд╕реЗрдЯ = utf-8, рд╕рд╛рдордЧреНрд░реА-рдкреНрд░рдХрд╛рд░: рдорд▓реНрдЯреАрдкрд╛рд░реНрдЯ / рдлреЙрд░реНрдо-рдбреЗрдЯрд╛; рд╕реАрдорд╛ = рдХреБрдЫ, рдЖрджрд┐) рд╡реИрдХрд▓реНрдкрд┐рдХред

рдПрдиреЛрдЯреЗрд╢рди @RequestParam - рдЕрдиреБрд░реЛрдз рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдкреИрд░рд╛рдореАрдЯрд░ рдХрд╛ рдирд╛рдо рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред рдЪреВрдБрдХрд┐ рдкреНрд░рддрд┐рдмрд┐рдВрдм рдХреЗ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдорд╛рдзреНрдпрдореЛрдВ рджреНрд╡рд╛рд░рд╛ рд╡рд┐рдзрд┐ рдкреИрд░рд╛рдореАрдЯрд░ рдХрд╛ рд╡рд░реНрддрдорд╛рди рдирд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЕрд╕рдВрднрд╡ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдЬрд╛рд╡рд╛рд╕реНрд╕рд┐рд╕реНрдЯ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд▓рд╕реА рдерд╛, рдЬрд┐рд╕реЗ asm рдХреЗ рд╕рд╛рде рдорд┐рд▓рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рдерд╛ред рдЗрд╕рд▓рд┐рдП, рдЕрдиреБрд░реЛрдз рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдЗрд╕ рдкреИрд░рд╛рдореАрдЯрд░ рдорд╛рдиреЛрдВ рдХреЛ рдПрдореНрдмреЗрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреИрд░рд╛рдореАрдЯрд░ рдХрд╛ рдирд╛рдо рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдРрд╕реА рд╡рд┐рдзрд┐ред GET рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдирд╛рд▓реЙрдЧ рд╣реИ - @PathVariable - рдСрдкрд░реЗрд╢рди рдХрд╛ рдПрдХ рд╣реА рд╕рд┐рджреНрдзрд╛рдВрдд ( POST рдХреЗ рд╕рд╛рде рд╕рдВрдЧрдд рдирд╣реАрдВ)ред
@ рдХреНрд░реЗрдбреЗрдВрд╢рд┐рдпрд▓ рдПрдиреЛрдЯреЗрд╢рди - рдЕрдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд╡рд░реНрддрдорд╛рди рдбреЗрдЯрд╛ рдХреЛ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ, рдЕрдиреНрдпрдерд╛ рдпрджрд┐ рдЕрдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдЬрд╛рдирдХрд╛рд░реА рд╕рддреНрд░ рдореЗрдВ рдирд╣реАрдВ рд╣реИ, рддреЛ рдпрд╣ рд╢реВрдиреНрдп рд╣реЛ рд╕рдХрддреА рд╣реИред
рдЕрдиреБрд░реЛрдз рд╡рд░реНрдЧ рдкреНрд░рдгрд╛рд▓реА рдПрдХ рдЖрдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреБрд░реЛрдз рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╡рд░реНрддрдорд╛рди рдЬрд╛рдирдХрд╛рд░реА рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдХреЛрдХрд╛, рд╣реЗрдбрд░ рдФрд░ рдПрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЪреИрдирд▓ рд╢рд╛рдорд┐рд▓ рд╣реИ, рдЬрд┐рд╕реЗ рдмрд╛рдж рдореЗрдВ рдкреБрд╢ рдореИрд╕реЗрдЬ рдХреЛ рднреЗрдЬрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ... рдЬрд┐рдирдХреЗ рдкрд╛рд╕ рдЗрд╕ рд╕рдВрдмрдВрдз рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХреА рдлрдВрддрд╛рд╕реА рд╣реИред
рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╡рд░реНрдЧ ModelAndView рдПрдХ рдкреГрд╖реНрда рдореЙрдбрд▓ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдмрд┐рдирд╛ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХреЗ рд╕рдВрд╕рд╛рдзрди рдХрд╛ рдирд╛рдо рд╣реИ, рдФрд░ рд╕рдВрд╕рд╛рдзрди рдореЗрдВ рдПрдореНрдмреЗрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реИред


рдпрд╣ рд╕рдм рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдирд╣реАрдВ - рдЖрдкрдХреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рдорд╛рдирдЪрд┐рддреНрд░рдг рдХреЛ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред


 package org.examples.webapp.config; import org.ioc.annotations.configuration.Property; import org.ioc.annotations.configuration.PropertyFunction; import org.ioc.web.security.configuration.HttpContainer; import org.ioc.web.security.configuration.SecurityConfigureProcessor; import org.ioc.web.security.encoder.Encoder; import org.ioc.web.security.encoder.bcrypt.BCryptEncoder; import org.ioc.web.security.filter.CorsFilter; import org.ioc.web.security.filter.CsrfFilter; @Property public class SecurityConfig implements SecurityConfigureProcessor { @Override public void configure(HttpContainer httpContainer) { httpContainer. configureRequests(). anonymousRequests("/", "/signup", "/signin"). resourceRequests("/static/**"). authorizeRequests("/loginPage", "ROLE_USER"). authorizeRequests("/signout", "ROLE_USER"). and(). configureSession(). expiredPath("/"); } @PropertyFunction public CsrfFilter csrfFilter() { return new CsrfFilter(); } @PropertyFunction public CorsFilter corsFilter() { return new CorsFilter(); } @PropertyFunction public Encoder encoder() { return new BCryptEncoder(); } } 

** рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг:
@Property рдПрдиреЛрдЯреЗрд╢рди - рд╕рдВрджрд░реНрдн рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рд╣реИ рдФрд░ рдЗрд╕реЗ рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдПрдиреЛрдЯреЗрд╢рди @PropertyFunction - рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдХреЛ рд╕реВрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдХреБрдЫ рдкреНрд░рдХрд╛рд░ рджреЗрддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдПрдХ рдШрдЯрдХ (рдмрд┐рди) рдХреЗ рд░реВрдк рдореЗрдВ рдЖрд░рдВрдн рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЗрдВрдЯрд░рдлрд╝реЗрд╕ SecurityConfigureProcessor - рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдорд╛рдирдЪрд┐рддреНрд░рдг рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдЙрдкрдпреЛрдЧрд┐рддрд╛ред
HttpContainer рдореЙрдбрд▓ рд╡рд░реНрдЧ рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╣реИ рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рджреНрд╡рд╛рд░рд╛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдорд╛рдирдЪрд┐рддреНрд░рдг рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИред
CsrfFilter рд╡рд░реНрдЧ рдЕрдорд╛рдиреНрдп рдЕрдиреБрд░реЛрдзреЛрдВ (CSRF рдпрд╛рдВрддреНрд░рд┐рдХреА рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди) рдХрд╛ рдПрдХ рдлрд╝рд┐рд▓реНрдЯрд░ рд╣реИред
CorsFilter рдХреНрд▓рд╛рд╕ рдПрдХ рдХреНрд░реЙрд╕- рдУрд░рд┐рдЬрд┐рдирд▓ рд░рд┐рд╕реЛрд░реНрд╕ рд╢реЗрдпрд░рд┐рдВрдЧ рдлрд╝рд┐рд▓реНрдЯрд░ рд╣реИред


AnonymousRequests рдлрд╝рдВрдХреНрд╢рди - рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдПрдХ рдЕрд╕реАрдорд┐рдд рд╕рд░рдгреА рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдФрд░ рд░реЛрд▓ рдЪреЗрдХрд┐рдВрдЧ (ROLE_ANONYMOUS) рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред
ResourceRequests рдлрд╝рдВрдХреНрд╢рди - рдЕрд╕реАрдорд┐рдд рд╕рд░рдгреА рдЕрдиреБрд░реЛрдзреЛрдВ рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╕рдВрд╕рд╛рдзрди рдлрд╝рд╛рдЗрд▓ рдХрд┐рд╕ рдкрде рдкрд░ рд╣реЛрдЧреА рдЬрд┐рд╕реЗ рдЬрдЯрд┐рд▓ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг (рд╕реАрдПрд╕рдПрд╕, рдЬреЗрдПрд╕, рдЪрд┐рддреНрд░, рдЖрджрд┐) рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред
рдлрдВрдХреНрд╢рди рдСрдерд░рд╛рдЗрдЬрд╝рдкреНрд░рд┐рд╕реЗрд╕ - рдЕрд╕реАрдорд┐рдд рдЕрдиреБрд░реЛрдзреЛрдВ рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдореЗрдВ рдирд┐рд╣рд┐рдд рд╡рд┐рд╢рд┐рд╖реНрдЯ рднреВрдорд┐рдХрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред
рд╕рдордп-рд╕рдордп рдкрд░ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЪреБрдХреЗ рд╕рддреНрд░ рдХреЛ рдХреНрд▓рд┐рдпрд░ рдХрд░рддреЗ рд╕рдордп рдПрдХреНрд╕рдкрд╛рдпрд░рдбрдкреИрде рдлрд╝рдВрдХреНрд╢рди - рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрд╕ рдореИрдкрд┐рдВрдЧ (рд░реАрдбрд╛рдпрд░реЗрдХреНрдЯ рд▓рд┐рдВрдХ) рджреНрд╡рд╛рд░рд╛ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рд╣реЛрддрд╛ рд╣реИред


рдЦреИрд░, рдкреГрд╖реНрда, рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдФрд░ рд╕рд╛рдЗрдЯ рд╢реИрд▓рд┐рдпрд╛рдБ рдереАрдВ (рдореИрдВ рдЧрд╣рд░рд╛рдИ рддрдХ рдирд╣реАрдВ рдЧрдпрд╛)ред


рд╕реНрдкрд╛рдпрд▓рд░ рд╣реЗрдбрд┐рдВрдЧ

index.vm - рдореБрдЦреНрдп рдкреГрд╖реНрда


 <html> <head> <meta charset="utf-8"/> <title>IoC Test</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/style.css"/> <link rel="stylesheet" href="/static/css/pnotify.custom.min.css"/> <link rel="stylesheet" href="/static/css/pnotify.css"/> <link rel="stylesheet" href="/static/css/pnotify.buttons.css"/> </head> <body> <div class="container"> <h1>IoC Starter Test</h1> <br> <h4>Create user</h4> <br> <form id="creation"> <label for="username">Username: </label> <input type="text" id="username" name="username" class="color-input-field"/> <label for="password">Password: </label> <input type="password" id="password" name="password" class="color-input-field"/> <label for="repeatedPassword">Repeate: </label> <input type="password" id="repeatedPassword" name="repeatedPassword" class="color-input-field"/> <button type="button" class="btn btn-success btn-create">Sing up!</button> </form> <h4>Authenticate</h4> <br> <form id="auth"> <label for="username">Username: </label> <input type="text" id="username" name="username" class="color-input-field"/> <label for="password">Password: </label> <input type="password" id="password" name="password" class="color-input-field"/> <button type="button" class="btn btn-danger btn-auth">Sing in!</button> </form> </div> <script type="text/javascript" src="/static/js/jquery.js"></script> <script type="text/javascript" src="/static/js/bootstrap.min.js"></script> <script type="text/javascript" src="/static/js/scripts.js"></script> <script type="text/javascript" src="/static/js/pnotify.js"></script> <script type="text/javascript" src="/static/js/pnotify.buttons.js"></script> </body> </html> 

рдЕрдзрд┐рдХреГрдд.vm - рдПрдХ рдЕрдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП


 <html> <head> <meta charset="utf-8"/> <title>IoC Test</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/style.css"/> <link rel="stylesheet" href="/static/css/pnotify.custom.min.css"/> <link rel="stylesheet" href="/static/css/pnotify.css"/> <link rel="stylesheet" href="/static/css/pnotify.buttons.css"/> </head> <body> <div class="container"> <h1>Authorized page</h1> <br> <h4>Test auth data</h4> <div id="auth_data"> #if($!account) <h4>Hello @$!account.username, You successfully authenticated!</h4> <br> <button type="button" class="btn btn-success btn-logout">Logout!</button> #end </div> </div> <script type="text/javascript" src="/static/js/jquery.js"></script> <script type="text/javascript" src="/static/js/bootstrap.min.js"></script> <script type="text/javascript" src="/static/js/scripts.js"></script> <script type="text/javascript" src="/static/js/pnotify.js"></script> <script type="text/javascript" src="/static/js/pnotify.buttons.js"></script> </body> </html> 

script.js - рдирд┐рдпрдВрддреНрд░рдХ, рд╕рд░реНрд╡рд░ рдХреЛ рдЕрдиреБрд░реЛрдз рдЬрд╛рдирдХрд╛рд░реА рднреЗрдЬрдиреЗ рдФрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП


 $(function () { $(".btn-create").click(function () { var cooki = cookie(); document.cookie = 'CSRF-TOKEN=' + cooki; $.ajax({ url: "/signup", data: $('#creation').serialize(), headers: {'X-CSRF-TOKEN': cooki}, crossDomain: true, xhrFields: { withCredentials: true }, type: "POST" }).done(function (data) { switch (data.type) { case 'OK': new PNotify({ title: 'Success', text: data.message, type: 'success', hide: false }); break; case 'ERROR': new PNotify({ title: 'Error', text: data.message, type: 'error', hide: false }); break; } }); }); $(".btn-auth").click(function () { var cooki = cookie(); document.cookie = 'CSRF-TOKEN=' + cooki; $.ajax({ url: "/signin", data: $('#auth').serialize(), headers: {'X-CSRF-TOKEN': cooki}, crossDomain: true, xhrFields: { withCredentials: true }, type: "POST" }).done(function (data) { switch (data.type) { case 'OK': new PNotify({ title: 'Success', text: data.message, type: 'success', hide: false }); setTimeout(function () { window.location = "/loginPage"; }, 5000); break; case 'ERROR': new PNotify({ title: 'Error', text: data.message, type: 'error', hide: false }); break; } }); }); $(".btn-logout").click(function () { $.ajax({ url: "/signout", crossDomain: true, xhrFields: { withCredentials: true }, type: "GET" }).done(function (data) { switch (data.type) { case 'OK': new PNotify({ title: 'Success', text: 'Logouting...', type: 'success', hide: false }); setTimeout(function () { window.location = data.message; }, 5000); break; case 'ERROR': new PNotify({ title: 'Error', text: data.message, type: 'error', hide: false }); break; } }); }); }); function cookie(a) { return a // if the placeholder was passed, return ? ( // a random number from 0 to 15 a ^ // unless b is 8, Math.random() // in which case * 16 // a random number from >> a / 4 // 8 to 11 ).toString(16) // in hexadecimal : ( // or otherwise a concatenated string: [1e7] + // 10000000 + -1e3 + // -1000 + -4e3 + // -4000 + -8e3 + // -80000000 + -1e11 // -100000000000, ).replace( // replacing /[018]/g, // zeroes, ones, and eights with cookie // random hex digits ) } 

рд╕рдВрдХрд▓рди рдХрд░реЗрдВ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЬреЛ рдХреБрдЫ рднреА рд╣реИ рдЙрд╕реЗ рдЪрд▓рд╛рдПрдВред
рдпрджрд┐ рд╕рдм рдХреБрдЫ рд╕рд╣реА рд╣реИ, рддреЛ рд╣рдо рдбрд╛рдЙрдирд▓реЛрдб рдХреЗ рдЕрдВрдд рдореЗрдВ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджреЗрдЦреЗрдВрдЧреЗ:


рд▓реЙрдЧ рдлрд╝рд╛рдЗрд▓

[реирез.резрез.рез] реиреи: реи реп: релрез: реп реж реп] рдЗрдирдлреЛ web.model.mapping.MappingContainer: рдореИрдк рдХрд┐рдпрд╛ рд╣реБрдЖ рддрд░реАрдХрд╛ [/], рд╡рд┐рдзрд┐ = [GET], рд╕реЗ [рдкрдмреНрд▓рд┐рдХ org.ioc.web.model.odelAndView org.examples.webapp рдкрд░ред .Mapping.ainMapping.index ()]
[реирез.резреж.рез] реиреи: реи реп: релрез: репреп рей] INFO web.model.mapping.MappingContainer: рдореИрдк рдХрд┐рдпрд╛ рд╣реБрдЖ рддрд░реАрдХрд╛ [/ signup], рд╡рд┐рдзрд┐ = [POST], [public org.examples.webapp.responces.IMessage org.examples рдкрд░ред webapp.mapping.MainMapping.createUser (java.lang.String, java.lang.String, java.lang.String)]
[реирез.резрез.рез] реиреи: реи реп: релрез: репреп рей] рдЗрдиреНрдлреЛ рд╡реЗрдм рд╡реЗрдмрдореЛрдбрд┐рдВрдЧред рдореИрдкрд┐рдВрдЧ рдХреЙрдиреНрдЯреЗрдХрд░: рдореИрдкреНрдб рд╡рд┐рдзрд┐ [/ рд╕рд╛рдЗрдирдЗрди], рд╡рд┐рдзрд┐ = [рдкреЛрд╕реНрдЯ], рд╕реЗ [рдкрдмреНрд▓рд┐рдХ org.examples.webapp.responces.IMessage org.examplesред webapp.mapping.MainMapping.auth (org.ioc.web.model.http.Request, java.lang.String, java.lang.String)]
[реирез.резреж.рез] реиреи: реи реп: релрез: репреп рей] INFO web.model.mapping.MappingContainer: рдореИрдкреНрдб рд╡рд┐рдзрд┐ [/ рд╕рд╛рдЗрдирдЖрдЙрдЯ], рд╡рд┐рдзрд┐ = [GET], рд╕реЗ [рдкрдмреНрд▓рд┐рдХ org.examples.webapp.responces.IMessage org.examples рддрдХред webapp.mapping.MainMapping.signout (org.ioc.web.model.http.Request)]
[реирез.резрез.рез] реиреи: реи реп: релрез: репреп рел] INFO web.model.mapping.MappingContainer: рдореИрдк рдХреА рдЧрдИ рд╡рд┐рдзрд┐ [/ loginPage], рд╡рд┐рдзрд┐ = [GET], [public org.ioc.web.odel.ModelAndView org.examples рдкрд░ред webapp.mapping.MainMapping.authenticated (org.examples.webapp.domain.entity.TblAccount)]
[реирез.резрез.рез] реиреи: реи реп: релрез: репреп INF] INFO ioc.web.factory.HttpInitializerFactory: Http рд╕рд░реНрд╡рд░ рдкреЛрд░реНрдЯ (рдУрдВ) рдкрд░ рд╢реБрд░реВ рд╣реБрдЖ: (реж (рез (http)


рдкрд░рд┐рдгрд╛рдо:
1) рд╣реЛрдо рдкреЗрдЬ
рд╕реВрдЪреА
2) рдкрдВрдЬреАрдХрд░рдг
рд╕рд╛рдЗрдирдЕрдк
3) рдкреНрд░рдорд╛рдгреАрдХрд░рдг
рдкреНрд░рдорд╛рдгрди
4) рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдкрд░рд┐рдгрд╛рдо рд╡рд╛рд▓рд╛ рдкреГрд╖реНрда (рд▓реЙрдЧрд┐рди рдФрд░ рдкрд╛рд╕рд╡рд░реНрдб рд╕рд╣реА рдврдВрдЧ рд╕реЗ рджрд░реНрдЬ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд)
рдкрд░рд┐рдгрд╛рдо
5) рд╕рддреНрд░ рд╕реЗ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рд╕рд╛рдлрд╝ рдХрд░рдирд╛ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдкреНрд░рд╛рд░рдВрдн рдкреГрд╖реНрда рдкрд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░рдирд╛
рдЫрд╡рд┐
6) рдЕрдирдзрд┐рдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рджреНрд╡рд╛рд░рд╛ рд╕рддреНрд░ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕рд╛рде рдкреГрд╖реНрда рдкрд░ рдкрд╣реБрдВрдЪрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕
рдЫрд╡рд┐


рдЕрдВрдд


рдпрд╣ рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╡рд┐рдХрд╕рд┐рдд рд╣реЛ рд░рд╣реА рд╣реИ, "рдпреЛрдЧрджрд╛рдирдХрд░реНрддрд╛рдУрдВ" рдФрд░ рдореВрд▓ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХрд╛ рд╕реНрд╡рд╛рдЧрдд рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рдЕрдХреЗрд▓реЗ рдХрд░рдирд╛ рдХрдард┐рди рд╣реИред
рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА ред
рдкреНрд░рд╕рдВрдЧ
рдУрдЖрд░рдПрдо рдлреИрдХреНрдЯреНрд░реА
рд╡реЗрдм рдлреИрдХреНрдЯреНрд░реА
рдЙрджрд╛рд╣рд░рдг
рд▓реЗрдЦ рд╕реЗ рд╡рд░реНрддрдорд╛рди рдЙрджрд╛рд╣рд░рдг
рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдкрд░ рднреА 'рдЙрджрд╛рд╣рд░рдг' рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рд╕рднреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдЙрджрд╛рд╣рд░рдг рд╣реИрдВ , рдФрд░ рдЬреИрд╕рд╛ рдХрд┐ рд╡реЗ рдХрд╣рддреЗ рд╣реИрдВ, "рдЧреБрдб рд▓рдХ, рдордЬрд╝реЗ рдХрд░реЗрдВ", рдЖрдк рд╕рднреА рдХрд╛ рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред

Source: https://habr.com/ru/post/hi427247/


All Articles