Quickstart гайд по Spring + Java EE + Persistence, без XML

от автора

Привет, хабрахабр!

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

Итак, если вам хочется попробовать Spring MVC со сохранением в базе и 0(нулем) файлов xml-конфигураций, прошу под кат!

Конечно хотелось бы сразу запустить приложение, но сначала немного подготовимся.

1. Подготовка к запуску

1.1 IDE

Вся разработка будет вестись на Intellij IDEA, но не думаю что реализация в другой IDE будет сильно сложнее.

1.2 Структура папок

Сначала создадим папку проекта, назовем ее ForHabrahabr
Для нашего проекта в корне нужно создать вот такое дерево папок:
directories tree
(можно же просто сделать по инструкции для остальных в следующем разделе)

1.3 Gradle & Git

Для самостоятельных

Итак, каркас приложения мы получили.
Теперь добавим в него контроль версий и сборщик.
Для этого в ForHabrahabr добавим .gitignore с вот таким содержанием
.idea
*.iml
build/

Заходим в эту директорию через консоль и пишем

 git init 

Теперь добавим bulid.gradle со всеми зависимостями которые нам пригодятся в процессе написания приложения.

build.gradle

buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath(«org.springframework.boot:spring-boot-gradle-plugin:1.2.5.RELEASE»)

classpath ‘mysql:mysql-connector-java:5.1.34’
}
}

apply plugin: ‘java’
apply plugin: ‘eclipse’
apply plugin: ‘idea’
apply plugin: ‘spring-boot’

jar {
baseName = ‘gs-rest-service’
version = ‘0.1.0’
}

repositories {
mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
compile(«org.springframework.boot:spring-boot-starter-web»)
compile(«org.springframework.boot:spring-boot-starter-data-jpa»)
compile(«org.springframework.boot:spring-boot-starter-security»)
compile(«org.springframework.boot:spring-boot-starter-thymeleaf»)
compile ‘mysql:mysql-connector-java:5.1.31’
compile ‘commons-dbcp:commons-dbcp:1.4’
testCompile(«org.springframework:spring-test»)
testCompile(«junit:junit»)
testCompile ‘org.springframework.security:spring-security-test:4.0.1.RELEASE’
}

task wrapper(type: Wrapper) {
gradleVersion = ‘2.3’
}

После чего в консольке в той же директории где build.gradle пишем

 gradle wrapper ./gradlew build     (или для windows ./gradlew.bat build)  

Теперь можно использвать gradlew.bat/gradlew в зависимости от ОС.

1.3.1 Для остальных
  • Заходите через консоль в папку где находятся ваши проекты Idea
  • git clone github.com/MaxPovver/ForHabrahabr.git
  • git cd ForHabrahabr/
  • git checkout quikstart
  • Все, теперь у вас есть готовая структура проекта 🙂

1.4 База данных

В качестве БД выберем MySQL как самую простую для quickstart. Создаем ее на localhost,
в ней создаем базу forhabrahabr, в дальнейшем в ней будем создавать таблички
users
roles
users_roles
posts
likes
Но об этом позже, пока достаточно создать БД.

2. Начинаем кодить

2.1 Создание проекта

Итак, для начала откроем наш только что созданный проект в Intellj IDEA, она увидит Gradle и предложит использовать его:
(Welcome to ItelliJ IDEA -> Open -> ForHabrahabr)
image
В этом окошке просто жмете ок, если его нет(или проблемы с Gradle JVM) — пишите в лс, буду разбираться что не так.

В итоге должен получиться такой проект:
image

2.2 Добавляем первый код

Первым делом создадим пакет для всех классов, назовем его habraspring(обычная папка в src/main/java/), а в нем — первый
класс Application

Код класса

package habraspring;  import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.data.jpa.repository.config.EnableJpaRepositories;  @SpringBootApplication @ComponentScan @EnableJpaRepositories(basePackages = {"habraspring"}) public class Application {     public static void main(String[] args) {         SpringApplication.run(Application.class, args);     } } 

Но в таком виде наше приложение еще не запустится, надо показать автоконфигуратору где находится база данных, для этого добавим файл в папку resources/ файл
application.properties

С вот таким содержанием

 #settings for database spring.datasource.url=jdbc:mysql://localhost/forhabrahabr spring.datasource.username=root spring.datasource.password= spring.datasource.driver-class-name=com.mysql.jdbc.Driver #turned on to enable lazy loading spring.jpa.properties.hibernate.enable_lazy_load_no_trans = true 

Также надо создать в resources/ папку templates/ для шаблонизатора.

Папка ресурсов будет выглядеть вот так
image
Не обращайте внимание на файлы .gitkeep, для работы программы они не нужны, можно их спокойно удалять/не создавать.

Готово, можете впервые запустить ваше приложение без падения 🙂
Для запуска нужно запустить таску bootRun(двойной клик по ней)
image
Если нет такой панельки, идем в View -> Tool Windows -> Gradle
В логе приложения будет что-то вроде такого:

Лог запуска

 15:24:47: Executing external task 'bootRun'... :compileJava UP-TO-DATE :processResources :classes :findMainClass :bootRun    .   ____          _            __ _ _  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )   '  |____| .__|_| |_|_| |_\__, | / / / /  =========|_|==============|___/=/_/_/_/  :: Spring Boot ::        (v1.2.5.RELEASE)  2015-07-11 14:24:49.180  INFO 12590 --- [           main] habraspring.Application                  : Starting Application on MacBook-Pro-Maksim.local with PID 12590 (/Users/admin/IdeaProjects/ForHabrahabr/build/classes/main started by admin in /Users/admin/IdeaProjects/ForHabrahabr) 2015-07-11 14:24:49.230  INFO 12590 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2eda0940: startup date [Sat Jul 11 14:24:49 MSK 2015]; root of context hierarchy 2015-07-11 14:24:50.029  INFO 12590 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]] 2015-07-11 14:24:50.701  INFO 12590 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [class org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$1f1e9ae] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2015-07-11 14:24:50.727  INFO 12590 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'transactionAttributeSource' of type [class org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2015-07-11 14:24:50.741  INFO 12590 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'transactionInterceptor' of type [class org.springframework.transaction.interceptor.TransactionInterceptor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2015-07-11 14:24:50.746  INFO 12590 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.config.internalTransactionAdvisor' of type [class org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2015-07-11 14:24:51.168  INFO 12590 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http) 2015-07-11 14:24:51.408  INFO 12590 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat 2015-07-11 14:24:51.409  INFO 12590 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.0.23 2015-07-11 14:24:51.601  INFO 12590 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext 2015-07-11 14:24:51.601  INFO 12590 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2374 ms 2015-07-11 14:24:52.570  INFO 12590 --- [ost-startStop-1] b.a.s.AuthenticationManagerConfiguration :   Using default security password: bd1659e1-4c49-43a2-9fd6-2ca7d46e9e23  2015-07-11 14:24:52.614  INFO 12590 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/css/**'], [] 2015-07-11 14:24:52.614  INFO 12590 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/js/**'], [] 2015-07-11 14:24:52.614  INFO 12590 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/images/**'], [] 2015-07-11 14:24:52.614  INFO 12590 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/**/favicon.ico'], [] 2015-07-11 14:24:52.614  INFO 12590 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/error'], [] 2015-07-11 14:24:52.650  INFO 12590 --- [ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/**']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@5854c7d0, org.springframework.security.web.context.SecurityContextPersistenceFilter@874f491, org.springframework.security.web.header.HeaderWriterFilter@34c74c36, org.springframework.security.web.authentication.logout.LogoutFilter@609329b3, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@a37632c, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@33a36df4, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@a3153e3, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1b8b1dc9, org.springframework.security.web.session.SessionManagementFilter@5ad0989a, org.springframework.security.web.access.ExceptionTranslationFilter@3e313564, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@1fb86c05] 2015-07-11 14:24:52.723  INFO 12590 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'characterEncodingFilter' to: [/*] 2015-07-11 14:24:52.724  INFO 12590 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 2015-07-11 14:24:52.724  INFO 12590 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'springSecurityFilterChain' to: [/*] 2015-07-11 14:24:52.724  INFO 12590 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/] 2015-07-11 14:24:53.410  INFO 12590 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default' 2015-07-11 14:24:53.425  INFO 12590 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [ 	name: default 	...] 2015-07-11 14:24:53.500  INFO 12590 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {4.3.10.Final} 2015-07-11 14:24:53.503  INFO 12590 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found 2015-07-11 14:24:53.505  INFO 12590 --- [           main] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist 2015-07-11 14:24:53.628  INFO 12590 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {4.0.5.Final} 2015-07-11 14:24:53.711  INFO 12590 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect 2015-07-11 14:24:53.774  INFO 12590 --- [           main] o.h.h.i.ast.ASTQueryTranslatorFactory    : HHH000397: Using ASTQueryTranslatorFactory 2015-07-11 14:24:54.244  INFO 12590 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2eda0940: startup date [Sat Jul 11 14:24:49 MSK 2015]; root of context hierarchy 2015-07-11 14:24:54.328  INFO 12590 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2015-07-11 14:24:54.328  INFO 12590 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest) 2015-07-11 14:24:54.356  INFO 12590 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2015-07-11 14:24:54.357  INFO 12590 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2015-07-11 14:24:54.393  INFO 12590 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2015-07-11 14:24:54.723  INFO 12590 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup 2015-07-11 14:24:54.800  INFO 12590 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http) 2015-07-11 14:24:54.803  INFO 12590 --- [           main] habraspring.Application                  : Started Application in 5.945 seconds (JVM running for 6.529)

Попробуйте теперь зайти по адресу http://localhost:8080, должен работать 🙂

Ну а теперь хотелось бы увидеть немного контента, не так ли?)

2.3 Контент

Для этого нам понадобится создать два класса конфигурации(помните, никаких XML!) во вложенной папке config, а также добавить home.html (аналог index.html) в папку resources.
Файлы конфигурации у нас простейшие, ведь мы их используем для страниц без контроллера:

config/MvcConfig.java

package habraspring.config;  import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  @Configuration public class MvcConfig extends WebMvcConfigurerAdapter {     @Override     public void addViewControllers(ViewControllerRegistry registry) {         registry.addViewController("/home").setViewName("home");         registry.addViewController("/").setViewName("home");     } } 

config/WebSecurityConfig.java

package habraspring.config;  import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; 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.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;  @Configuration @EnableWebMvcSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) public class WebSecurityConfig extends WebSecurityConfigurerAdapter {     @Override     protected void configure(HttpSecurity http) throws Exception {         http                 .authorizeRequests()                 .antMatchers("/", "/home").permitAll();     } } 

Ну и простейшая домашняя страничка:

home.html

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> <head>     <title>Habrahabr</title> </head> <body> <h1>Welcome!</h1>  <p>Yours home page.</p> </body> </html> 

Как должен выглядеть проект на этом этапе можно посмотреть(и скачать) тут:
github.com/MaxPovver/ForHabrahabr/tree/withbasicmvc

Если на данный момент все сделано правильно, по http://localhost:8080 у вас должно выводится

 Welcome!  Yours home page. 

3. Добавляем работу с БД

Итак, мы хотим добавить контроллеров, и чтобы доступ к ним выдавался только авторизованным юзерам, но у нас их пока нет 🙂

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

  • Добавить класс, описывающий сущность юзера в бд
  • Добавить репозиторий новой сущности
  • Добавить «связь» между механизмом Spring Security и нашей сущностью
  • Все везде зарегистрировать
  • «Включить» Spring Security

3.1 Сущность «User»

Сначала создадим в бд простейшую табличку users с полями id, username, password.

Теперь создадим подпакет entities для сущностей и создадим в нем класс User:

entities/User.java

package habraspring.entities;  import javax.persistence.*;  @Entity @Table(name="users") public class User {     @Id     @GeneratedValue(strategy = GenerationType.AUTO)     private long id;     private String username;     private String password;          public String getPassword() {         return password;     }      public void setPassword(String password) {         this.password = password;     }      public long getId() {         return id;     }      public void setId(long id) {         this.id = id;     }      public String getUsername() {         return username;     }      public void setUsername(String username) {         this.username = username;     }      protected User(){}     public User(String name, String pass) {         username = name;         password = pass;     }      } 

Никаких hbm.xml не нужно, даже аннотировать поля не нужно(исключение — поле ID, его всегда надо отмечать)

3.2 Репозиторий UsersRepository

Здесь Spring все делает за нас, достаточно отнаследоваться чтобы он понял что ему генерировать, код же писать не нужно вообще:

UsersRepository.java

package habraspring.repositories;  import habraspring.entities.User; import org.springframework.data.repository.CrudRepository;  public interface UsersRepository extends CrudRepository<User, Long> {     User findByUsername(String username); } 

3.3 Добавление связи между юзером и Spring Security

Для этого нам надо создать класс реализующий интерфейс UserDetailsService и подлючить его в WebSecurityConfig

utils/MySQLUserDetailsService.java

package habraspring.utils;  import habraspring.entities.User; import habraspring.repositories.UsersRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.core.GrantedAuthority; 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 java.util.ArrayList; import java.util.Collection; import java.util.List;  @Service public class MySQLUserDetailsService implements UserDetailsService {     @Autowired     UsersRepository users;     @Override     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {         UserDetails loadedUser;          try {             User client = users.findByUsername(username);             loadedUser = new org.springframework.security.core.userdetails.User(                     client.getUsername(), client.getPassword(),                     DummyAuthority.getAuth());         } catch (Exception repositoryProblem) {             throw new InternalAuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);         }         return loadedUser;     }      static class DummyAuthority implements GrantedAuthority     {         static Collection<GrantedAuthority> getAuth()         {             List<GrantedAuthority> res = new ArrayList<>(1);             res.add(new DummyAuthority());             return res;         }         @Override         public String getAuthority() {             return "USER";         }     } } 

Теперь изменим код WebSecurityConfig:

Заголовок спойлера

package habraspring.config;  import habraspring.utils.MySQLUserDetailsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; 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.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;  @Configuration @EnableWebMvcSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) public class WebSecurityConfig extends WebSecurityConfigurerAdapter {     @Override     protected void configure(HttpSecurity http) throws Exception {         http                 .authorizeRequests()                 .antMatchers("/", "/home").permitAll()                 .anyRequest().authenticated()                 .and()                 .formLogin()                 .loginPage("/login")                 .permitAll()                 .and()                 .logout()                 .permitAll();     }      @Autowired     private MySQLUserDetailsService mySQLUserDetailsService;      @Autowired     public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {         auth.userDetailsService(mySQLUserDetailsService);     } } 

Добавим страничку входа login.html и «секретную»(только для авторизованных) страничку secret.html

Их код

secret.html

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"       xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> <head>     <title>Secret page</title> </head> <body> <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1> <form th:action="@{/logout}" method="post">     <input type="submit" value="Sign Out"/> </form> </body> </html> 

login.html

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"       xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> <head>     <title>Login page</title> </head> <body> <div th:if="${param.error}">     Invalid username and password. </div> <div th:if="${param.logout}">     You have been logged out. </div> <form th:action="@{/login}" method="post">     <div><label> User Name : <input type="text" name="username"/> </label></div>     <div><label> Password: <input type="password" name="password"/> </label></div>     <div><input type="submit" value="Sign In"/></div> </form> </body> </html> 

И сделаем новые странички доступными без контроллера, добавив в WebMvcConfig 2 строчки:

        registry.addViewController("/login").setViewName("login");         registry.addViewController("/secret").setViewName("secret"); 

Готово! Теперь по адресу http://localhost:8080 у вас должно все выводиться нормально,
а вот по адресу localhost:8080/secret Вы пройти не сможете — будет кидать в /login, требуя валидную пару юзер/пароль.
Теперь добавьте в Вашу таблицу forhabrahabr.users запись c паролем и логином user, user (или запустите скрипт github.com/MaxPovver/ForHabrahabr/blob/withauth/import_me.sql в вашей дб).
Если вы все сделали правильно, теперь Вас должно пускать в /secret =)

4. К чему мы пришли

Итак, мы уже используем полноценное Spring MVC приложение с использованием Spring Security для безопасности и Spring JPA для работы с БД. И никаких XML =)

4.1 Для желающих запустить готовый проект

  • git clone github.com/MaxPovver/ForHabrahabr.git
  • cd ForHabrahabr/
  • git checkout withauth
  • запускаем в своей локальной mysql бд import_me.sql(или создаем руками табличку и данные для нее)
  • Открываем через IDEA созданную папку ForHabrahabr

    image
  • Нету панельки Gradle? Открываем ее тут

    image
  • Запускаем bootRun

    image
  • На этом шаге уже должно все работать

Многое пришлось опустить/не объяснять чтобы не запутать окончательно, но если считаете необходимым добавить что-то уже сейчас — пишите в лс.

Осталось материала еще минимум на одну часть, если, конечно, тема актуальна. (Controllers, EntityToEntity(ManyToOne OneToOne etc), User Roles etc)

Полезна ли статья?

Никто ещё не голосовал. Воздержавшихся нет.

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

ссылка на оригинал статьи http://habrahabr.ru/post/262323/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *