Spring, Spring Security, JPA, MySQL, конфигурация гибернации - PullRequest
0 голосов
/ 23 апреля 2020

Я работаю над проектом, который использует Spring Security, Hibernate, JPA, mySQL ... Я пытаюсь заставить мою регистрацию, вход в систему и выход из системы работать для этого проекта, и ни один из пользовательских вводов не сохраняется в базы данных, и так и не могу понять это, чтобы спасти мою жизнь. Я перепробовал почти все, что мог придумать, и пришел к выводу, что мне не хватает какой-то фундаментальной информации о том, как все это на самом деле работает. Мне неясно, должен ли я создавать таблицы и вставлять в них исходные данные перед тем, как запускать проект, или таблицы создаются и настраиваются с помощью приведенного ниже кода. Должно ли быть начальное создание таблицы в моей базе данных? Если это так ... как правильно создать эти таблицы, чтобы пользовательский ввод хранился в базе данных? Меня особенно смущает роль пользователей @JoinTable.

package com.stephanie.mycapec.models;

import java.util.Set;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "user")
public class User {
    public User() {
    }
    public User(Long id, String email, String password, String fullname, boolean enabled){
        this.id = id;
        this.email=email;
        this.password=password;
        this.fullname=fullname;
        this.enabled=enabled;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String email;

    private String password;

    private String fullname;

    private boolean enabled;

    @ManyToMany
    @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))

    private Set<Role> roles;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getFullname() {
        return fullname;
    }

    public void setFullname(String fullname) {
        this.fullname = fullname;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

    @Override
    public String toString(){
        return String.format("User[id=%d, email='%s', password='%s', name='%s'" );
    }


}

Нужно ли мне также инициализировать таблицу для users_roles в моей базе данных? Или таблица схемы создана @JoinTable?

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

2020-04-22 22:30:23.260  INFO 25452 --- [           main] com.stephanie.mycapec.MyCapecApp         : Starting MyCapecApp on DESKTOP-4G0GSBA with PID 25452 (C:\Users\Stephanie\My-Capec\build\classes\java\main started by Stephanie in C:\Users\Stephanie\My-Capec)
2020-04-22 22:30:23.263  INFO 25452 --- [           main] com.stephanie.mycapec.MyCapecApp         : No active profile set, falling back to default profiles: default
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.codehaus.groovy.vmplugin.v7.Java7$1 (file:/C:/Users/Stephanie/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.9/4222eafca660d01a44682c3fe4c629005728973/groovy-2.5.9.jar) to constructor java.lang.invoke.MethodHandles$Lookup(java.lang.Class,int)
WARNING: Please consider reporting this to the maintainers of org.codehaus.groovy.vmplugin.v7.Java7$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
2020-04-22 22:30:23.887  INFO 25452 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2020-04-22 22:30:23.887  INFO 25452 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
2020-04-22 22:30:23.919  INFO 25452 --- [           main] .RepositoryConfigurationExtensionSupport : Spring Data JDBC - Could not safely identify store assignment for repository candidate interface com.stephanie.mycapec.repositories.ApdbRepository. If you want this repository to be a JDBC repository, consider annotating your entities with one of these annotations: org.springframework.data.relational.core.mapping.Table.
2020-04-22 22:30:23.920  INFO 25452 --- [           main] .RepositoryConfigurationExtensionSupport : Spring Data JDBC - Could not safely identify store assignment for repository candidate interface com.stephanie.mycapec.repositories.RoleRepository. If you want this repository to be a JDBC repository, consider annotating your entities with one of these annotations: org.springframework.data.relational.core.mapping.Table.
2020-04-22 22:30:23.921  INFO 25452 --- [           main] .RepositoryConfigurationExtensionSupport : Spring Data JDBC - Could not safely identify store assignment for repository candidate interface com.stephanie.mycapec.repositories.UseCaseRepository. If you want this repository to be a JDBC repository, consider annotating your entities with one of these annotations: org.springframework.data.relational.core.mapping.Table.
2020-04-22 22:30:23.922  INFO 25452 --- [           main] .RepositoryConfigurationExtensionSupport : Spring Data JDBC - Could not safely identify store assignment for repository candidate interface com.stephanie.mycapec.repositories.UserRepository. If you want this repository to be a JDBC repository, consider annotating your entities with one of these annotations: org.springframework.data.relational.core.mapping.Table.
2020-04-22 22:30:23.922  INFO 25452 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 31ms. Found 0 JDBC repository interfaces.
2020-04-22 22:30:23.929  INFO 25452 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2020-04-22 22:30:23.929  INFO 25452 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2020-04-22 22:30:23.960  INFO 25452 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 28ms. Found 4 JPA repository interfaces.
2020-04-22 22:30:24.217  INFO 25452 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-04-22 22:30:24.388  INFO 25452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-04-22 22:30:24.394  INFO 25452 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-04-22 22:30:24.394  INFO 25452 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.30]
2020-04-22 22:30:24.523  INFO 25452 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-04-22 22:30:24.523  INFO 25452 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1115 ms
2020-04-22 22:30:24.685  INFO 25452 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2020-04-22 22:30:24.742  INFO 25452 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.4.10.Final}
2020-04-22 22:30:24.832  INFO 25452 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
2020-04-22 22:30:24.906  INFO 25452 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-04-22 22:30:25.208  INFO 25452 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-04-22 22:30:25.218  INFO 25452 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate: alter table role_users add constraint FKipeyaf3dve9njdrl1t23ndidv foreign key (users_id) references user (id)
Hibernate: alter table role_users add constraint FKele6ufqrv6w1uoxqw6h1vkki0 foreign key (role_id) references role (id)
Hibernate: alter table users_roles add constraint FKt4v0rrweyk393bdgt107vdx0x foreign key (role_id) references role (id)
Hibernate: alter table users_roles add constraint FKgd3iendaoyh04b95ykqise6qh foreign key (user_id) references user (id)
2020-04-22 22:30:25.927  INFO 25452 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-04-22 22:30:25.933  INFO 25452 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-04-22 22:30:25.980  WARN 25452 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2020-04-22 22:30:26.376  INFO 25452 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/resources/**'], []
2020-04-22 22:30:26.376  INFO 25452 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/static/**'], []
2020-04-22 22:30:26.376  INFO 25452 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/css/**'], []
2020-04-22 22:30:26.376  INFO 25452 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/js/**'], []
2020-04-22 22:30:26.376  INFO 25452 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: Ant [pattern='/images/**'], []
2020-04-22 22:30:26.399  INFO 25452 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1238a074, org.springframework.security.web.context.SecurityContextPersistenceFilter@6e12f38c, org.springframework.security.web.header.HeaderWriterFilter@5a4e492c, org.springframework.security.web.authentication.logout.LogoutFilter@240291d9, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@640a6d4b, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5a9baba8, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1b79df53, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@35b58254, org.springframework.security.web.session.SessionManagementFilter@26a202ae, org.springframework.security.web.access.ExceptionTranslationFilter@534d0cfa, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@49c4118b]
2020-04-22 22:30:26.517  INFO 25452 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-22 22:30:26.887  INFO 25452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-04-22 22:30:26.889  INFO 25452 --- [           main] com.stephanie.mycapec.MyCapecApp         : Started MyCapecApp in 3.887 seconds (JVM running for 4.6)
Hibernate: select role0_.id as id1_1_, role0_.role as role2_1_ from role role0_ where role0_.role=?
Hibernate: select role0_.id as id1_1_, role0_.role as role2_1_ from role role0_ where role0_.role=?
2020-04-22 22:30:32.835  INFO 25452 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-04-22 22:30:32.835  INFO 25452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2020-04-22 22:30:32.842  INFO 25452 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 7 ms
2020-04-22 22:30:33.050  WARN 25452 --- [nio-8080-exec-1] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [175] milliseconds.
2020-04-22 22:30:33.421  WARN 25452 --- [nio-8080-exec-2] n.n.u.t.expressions.ExpressionProcessor  : Fragment expression "default" is being wrapped as a Thymeleaf 3 fragment expression (~{...}) for backwards compatibility purposes.  This wrapping will be dropped in the next major version of the expression processor, so please rewrite as a Thymeleaf 3 fragment expression to future-proof your code.  See https://github.com/thymeleaf/thymeleaf/issues/451 for more information.
Hibernate: select user0_.id as id1_4_, user0_.email as email2_4_, user0_.enabled as enabled3_4_, user0_.fullname as fullname4_4_, user0_.password as password5_4_ from user user0_ where user0_.email=?

также вот мое application.properties

spring.datasource.url = jdbc:mysql://localhost:3306/login?useSSL=true
spring.datasource.username = root
spring.datasource.password = uber
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.database=H2
spring.jpa.properties.hibernate.jdbc.batch_size=5
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true

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

РЕДАКТИРОВАТЬ В соответствии с просьбой, вот моя роль сущности

package com.stephanie.mycapec.models;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "role")
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String role;

    @ManyToMany(targetEntity= User.class)
    //@ManyToMany(mappedBy = "role")
    private Set<User> users;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public Set<User> getUsers() {
        return users;
    }

    public void setUsers(Set<User> users) {
        this.users = users;
    }

}

Ответы [ 2 ]

0 голосов
/ 23 апреля 2020

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

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

и добавить @Transactional аннотацию к вашему CustomUserDetailService :

@Override
@Transactional
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {

    User user = userRepository.findByEmail(email);  
    if(user != null) {
        List<GrantedAuthority> authorities = getUserAuthority(user.getRoles());
        return buildUserForAuthentication(user, authorities);
    } else {
        throw new UsernameNotFoundException("username not found");
    }
}

Если вы тестируете со встроенными (в памяти) базами данных, такими как hsqldb или h2 , тогда Spring автоматически создаст для вас таблицы базы данных. Для других баз данных, таких как mySql или PostgreSql, вам придется явно указать Hibernate (через Spring) на создание или обновление объектов схемы. Это делается путем добавления этого свойства в ваш application.properties: spring.jpa.hibernate.ddl-auto = update.

Что касается связывания пользователей с ролями, да, вы должны сделать это либо с помощью ручных вставок, либо создать административную инструментальную панель в своем приложении, которая управляет пользователями и ролями. (типично для корпоративных приложений)

В этом конкретном случае Hibernate создаст три таблицы, которые называются user , role и users_roles . Последнее - связать пользователей с ролями из-за ассоциации ManyToMany.

Ваш код уже заполняет пользователя во время входа в систему, затем вам нужно каким-то образом предоставить соответствующие роли каждому пользователю, либо с помощью Панель администратора, которую я упомянул, или вставьте вручную.

Надеюсь, это поможет.

0 голосов
/ 23 апреля 2020

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

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

Таким образом, у вас должно быть две таблицы, которые выглядят так:

Пользователь:

id         bigint    not null    autoincrement
email      varchar   not null
password   varchar   not null
fullname   varchar   not null
enabled    boolean   not null    default false

Роль:

id         bigint    not null    autoincrement
role       varchar   not null

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

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

UserRoles:

id         bigint    not null    autonincrement
userid     bigint    not null
roleid     bigint    not null

Конечно, эта таблица должна иметь два ограничения внешнего ключа. С учетом этого ваши занятия могут выглядеть следующим образом:

Пользователь:

  @Entity
  @Table(name="user")
  public class User implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name="id")
  private Long id;

  @Column(name="fullname")
  private String fullname;

  @Column(name="password")
  private String password;

  @Column(name="enabled")
  private Boolean enabled;

  @Column(name="email")
  private String email;

  @JsonManagedReference
  @OneToMany(mappedBy="userid", cascade=CascadeType.ALL)
  @Fetch(value = FetchMode.SELECT)
  private List<UserRoles> roles = null;

  // Gettes & Setters etc.

}

Роль:

@Entity
@Table(name="role")
public class UserRole implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name="id")    
  private Long id;

  @Column(name="name")
  private String name;

  @JsonBackReference
  @OneToMany(mappedBy="roleid")
  @Fetch(value = FetchMode.JOIN)
  private List<UserRoles> users;

  // Getters & Setters

}

UserRole:

@Entity
@Table(name="userrole")
public class UserRoles implements Serializable{

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name="id")
  private Long id;

  @JsonBackReference
  @ManyToOne
  @JoinColumn(name="user_id")
  private User userid;

  @JsonManagedReference
  @ManyToOne
  @JoinColumn(name="role_id")
  private UserRole roleid;

  // Getters & Setters

}

Конечно, я пропустил некоторые части в классах, но моделирование работает таким образом. Теперь у вас есть место, где отношения хранятся в вашей базе данных, и вы смоделировали это в своей программе. Проверьте и настройте JSON настройки и стратегии выбора в соответствии с вашими потребностями.

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