I read the Spring Security documentation to learn how to create a basic authentication system for my web application but I don't understand what architecture to pick.
Link : https://docs.spring.io/spring-security/site/docs/5.1.5.RELEASE/reference/htmlsingle/#preface
Currently I'm using the class WebSecurityConfigurerAdapter with this code :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.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;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/css/**", "/index", "/user/**").permitAll()
//.antMatchers("/user/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").failureUrl("/login-error")
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("password")).roles("USER");
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
But in the documentation they recommand 3 alternative solutions.
1) WebMvcConfigurer :
https://docs.spring.io/spring-security/site/docs/5.1.5.RELEASE/reference/htmlsingle/#hello-web-security-java-configuration
2) AuthenticationManager :
https://docs.spring.io/spring-security/site/docs/5.1.5.RELEASE/reference/htmlsingle/#tech-intro-authentication
3) With another classes designed for Web Application (?)
https://docs.spring.io/spring-security/site/docs/5.1.5.RELEASE/reference/htmlsingle/#tech-intro-web-authentication
So, it's currently a big mess in my head and I don't know at all how to create my authentication system.
What architecture am I supposed to choose ?
Here my other classes in addition to understand my project :
UserService
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
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 org.springframework.transaction.annotation.Transactional;
import app.shellx.dao.AuthorityRepository;
import app.shellx.dao.RoleRepository;
import app.shellx.dao.UserRepository;
import app.shellx.model.Authority;
import app.shellx.model.Role;
import app.shellx.model.User;
#Service
public class UserService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleService roleService;
#Transactional(readOnly=true)
public User loadUserByUsername(final String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
//List<GrantedAuthority> authorities = buildUserAuthority(user.getAuthorities());
//if you're implementing UserDetails you wouldn't need to call this method and instead return the User as it is
//return buildUserForAuthentication(user, authorities);
return user;
}
/*public User login() {
try {
Authentication request = new UsernamePasswordAuthenticationToken(name, password);
Authentication result = am.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
break;
} catch(AuthenticationException e) {
System.out.println("Authentication failed: " + e.getMessage());
}
}
System.out.println("Successfully authenticated. Security context contains: " +
SecurityContextHolder.getContext().getAuthentication());
}
}*/
/* // Converts user to spring.springframework.security.core.userdetails.User
private User buildUserForAuthentication(User user, List<GrantedAuthority> authorities) {
return new User(user.getUsername(), user.getEmail(), user.getPassword(), authorities, user.isAccountNonExpired(), user.getAvatar());
}
private List<GrantedAuthority> buildUserAuthority(Set<Authority> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
// add user's authorities
for (Authority userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
}
List<GrantedAuthority> Result = new ArrayList()<GrantedAuthority>(setAuths);
return Result;
}*/
public void add(User user, String role) {
user.setRole(roleService.findByRole(role));
this.userRepository.save(user);
/*role.setAuthorities(authorities);
this.roleRepository.save(role);
for (Authority auth : authorities) {
auth.setRoles(role);
this.authorityRepository.save(auth);
}*/
}
public void update(User user) {
this.userRepository.save(user);
}
public String getCurrentUser() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username;
if (principal instanceof UserDetails) {
username = ((User)principal).getUsername();
} else {
username = principal.toString();
}
return username;
}
}
User
import java.time.LocalDate;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
#Entity
#Table(name="users")
public class User implements UserDetails {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "users_username", nullable = false, unique = true)
private String username;
#Column(name = "users_email", nullable = false, unique = true)
private String email;
#Column(name = "users_password")
private String password;
#Column(name = "users_enabled")
private boolean enabled;
#Column(name = "users_avatar")
private String avatar;
#Column(name = "users_date")
private LocalDate date;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
//#JoinTable(name = "authorities", joinColumns = #JoinColumn(name = "users_username"), inverseJoinColumns = #JoinColumn(name = "roles_username"))
private Role role;
public User() {
}
public User(String username, String email, String password, boolean enabled, String avatar) {
this.username = username;
this.email = email;
this.password = password;
this.enabled = enabled;
this.avatar = avatar;
}
public User(String username, String email, String password, Role role, boolean enabled, String avatar) {
this.username = username;
this.email = email;
this.password = password;
this.role = role;
this.enabled = enabled;
this.avatar = avatar;
}
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<Authority> authorities = new HashSet<Authority>();
authorities = role.getAuthorities();
return authorities;
}
public void setName(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public boolean isEnabled() {
return enabled;
}
public boolean isAccountNonExpired() {
return false;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return false;
}
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return false;
}
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 getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public String getRoleRole() {
return role.getRole();
}
}
EDIT : I'm using SPRING BOOT and Hibernate
Related
I'm trying make a test to Update User method that first get a User by id and after update the user , work it, but when I try to make a test in the Junit show me that couldn't find the user by Id. Can anyone help me, please?
UserClass
package br.com.projectsmanagement.entities;
import java.util.Date;
import java.util.Objects;
import jakarta.persistence.*;
#Entity
#Table(name = "tb_users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String password;
#Temporal(TemporalType.TIMESTAMP)
private Date dataCadastro;
public User() {
}
public User(String name, String email, String password, Date dataCadastro) {
this.name = name;
this.email = email;
this.password = password;
this.dataCadastro = dataCadastro;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
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 Date getDataCadastro() {
return dataCadastro;
}
public void setDataCadastro(Date dataCadastro) {
this.dataCadastro = dataCadastro;
}
#Override
public int hashCode() {
return Objects.hash(id);
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
return Objects.equals(id, other.id);
}
}
UserServiceImpl
#Override
public User updateUser(Long id, User user) {
try {
User userUpdated = userRepository.findById(id).get();
userUpdated.setName(user.getName());
userUpdated.setPassword(user.getPassword());
return userRepository.saveAndFlush(userUpdated);
} catch (NoSuchElementException e) {
throw new InvalidIdException("Usuário não encontrado!");
}
}
And finally my UserServiceImplTest
package br.com.projectsmanagement.services.impl;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import br.com.projectsmanagement.entities.User;
import br.com.projectsmanagement.exception.EmailExistException;
import br.com.projectsmanagement.repositories.UserRepository;
#SpringBootTest
class UserServiceImplTest {
#InjectMocks
private UserServiceImpl userServiceImpl;
#Mock
private UserRepository userRepository;
private User user;
private Optional<User> optionalUser;
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
startUser();
}
#Test
void whenFindAllThenReturnAnListofUsers() {
when(userRepository.findAll()).thenReturn(List.of(user));
List<User> response = userServiceImpl.listUsers();
assertNotNull(response);
assertEquals(1, response.size());
assertEquals(User.class, response.get(0).getClass());
}
#Test
void whenFindByIdThenReturnAnUserInstance() {
when(userRepository.findById(anyLong())).thenReturn(optionalUser);
Optional<User> response = userServiceImpl.getUserById(1L);
assertThat(response).isPresent();
assertEquals(optionalUser.getClass(), response.getClass());
assertEquals(optionalUser.get().getName(), "Valdir");
}
#Test
void whenRegisterThenReturnSuccess() {
when(userRepository.saveAndFlush(any())).thenReturn(user);
User response = userServiceImpl.registerUser(user);
assertNotNull(response);
assertEquals(User.class, response.getClass());
assertEquals(user.getId(), response.getId());
}
#Test
void whenRegisterThenReturnAnEmailExistException() {
when(userRepository.findByEmail(anyString())).thenReturn(user);
try {
userServiceImpl.registerUser(user);
} catch (ClassCastException e) {
assertEquals(EmailExistException.class, e.getClass());
assertEquals("Esse e-mail já está cadastrado!", e.getMessage());
}
User response = userServiceImpl.registerUser(user);
assertNotNull(response);
assertEquals(User.class, response.getClass());
assertEquals(user.getId(), response.getId());
}
#Test
void whenUpdateThenReturnSuccess() {
when(userRepository.saveAndFlush(any())).thenReturn(user);
User response = userServiceImpl.updateUser(1L, user);
assertNotNull(response);
assertEquals(User.class, response.getClass());
}
#Test
void testDeleteUser() {
fail("Not yet implemented");
}
private void startUser() {
user = new User("Valdir", "valdir#gmail.com", "123456", new Date());
optionalUser = Optional.of(new User("Valdir", "valdir#gmail.com", "123456", new Date()));
}
}
I modified my class many times, but even doesn't work it
I think in your test case whenUpdateThenReturnSuccess(), you forgot to mock the userRepository.findById(id) that you call when updating your user.
If not mocked, it returns null.
#Test
void whenUpdateThenReturnSuccess() {
when(userRepository.findById(anyLong())).thenReturn(optionalUser);
when(userRepository.saveAndFlush(any(User.class))).thenReturn(user);
User response = userServiceImpl.updateUser(1L, user);
assertNotNull(response);
assertEquals(User.class, response.getClass());
}
Here is a sample entity and a repository in a Spring Boot application. I'm trying to test it. I need to commit all changes inside each test and rollback them after the test is finished.
If I remove #Transactional(propagation = Propagation.NOT_SUPPORTED) then the changes not commited at all. And I don't get an exception when insert users with the same email and emailIsUnique is failed. If I add this annotation, then changes are commited and emailIsUnique is passed. But userIsCreatedAndRead is failed, because user John Doe is already created in emailIsUnique and not rollbacked.
How to fix it?
package com.example.springdata.entities;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.hibernate.annotations.NaturalId;
#Entity(name = "Users")
public class UserEntity {
#Id
#GeneratedValue
private UUID id;
#NaturalId
#Column(length = 100, unique = true)
#NotNull
#Size(min = 3, max = 100)
private String login;
#Column(length = 100, unique = true)
#Email
private String email;
#Column(length = 100)
private String firstName;
#Column(length = 100)
private String lastName;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
package com.example.springdata.repositories;
import java.util.UUID;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import com.example.springdata.entities.UserEntity;
#RepositoryRestResource(path = "users", collectionResourceRel = "users")
public interface UserRepository extends CrudRepository<UserEntity, UUID> {
}
package com.example.springdata.repositories;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.example.springdata.entities.UserEntity;
import io.zonky.test.db.AutoConfigureEmbeddedDatabase;
import io.zonky.test.db.AutoConfigureEmbeddedDatabase.DatabaseProvider;
#DataJpaTest
#AutoConfigureEmbeddedDatabase(provider = DatabaseProvider.ZONKY)
#Transactional(propagation = Propagation.NOT_SUPPORTED)
class UserRepositoryIntegrationTests {
#Autowired
private UserRepository userRepository;
#Test
void userIsCreatedAndRead() {
UserEntity user = createEntity1();
userRepository.save(user);
assertThat(user.getId()).isNotNull();
Optional<UserEntity> optionalUser = userRepository.findById(user.getId());
assertThat(optionalUser).isPresent();
optionalUser.ifPresent(foundUser -> assertThat(foundUser).usingRecursiveComparison().isEqualTo(user));
}
#Test
void emailIsUnique() {
UserEntity user1 = createEntity1();
userRepository.save(user1);
UserEntity user2 = createEntity2();
user2.setEmail(user1.getEmail());
assertThrows(DataIntegrityViolationException.class, () -> userRepository.save(user2));
}
private UserEntity createEntity1() {
UserEntity user = new UserEntity();
user.setLogin("john"); //$NON-NLS-1$
user.setFirstName("John"); //$NON-NLS-1$
user.setLastName("Doe"); //$NON-NLS-1$
user.setEmail("john.doe#example.com"); //$NON-NLS-1$
return user;
}
private UserEntity createEntity2() {
UserEntity user = new UserEntity();
user.setLogin("jane"); //$NON-NLS-1$
user.setFirstName("Jane"); //$NON-NLS-1$
user.setLastName("Smith"); //$NON-NLS-1$
user.setEmail("jane.smith#example.com"); //$NON-NLS-1$
return user;
}
}
I'm trying to set all the values of a column of my H2 bank to false at 1:00 PM, but I'm having difficulties doing that, the message is being printed on the console, but the votes remain as TRUE.
My table looks like this, I would like every day at 1:00PM the values of the VOTED field to be FALSE
ID
EMAIL
PASSWORD
NAME
VOTED
1
bruno#gmail.com
$2a$10$j1Eic8Okp.IczSVQbU.ru.s.dXoxd1fdzWtK2os9oE9y9ZO8wvMx6
Bruno
TRUE
2
james#gmail.com
$2a$10$F/KLm5ULaNRVEL/K6MMeveZXr770G5cI3S7HZnEw.b7TZDENkCWBC
James
TRUE
3
robert#gmail.com
$2a$10$uHZjSrroGBtRBB/V.norRuOcDVz42MXnm0/2yLPGpE3P5XtPRo7L6
Robert
FALSE
This is the logic I'm using in my UserServices.java
Despite the project running, users remain as TRUE after the time determined in #Scheduled
#Scheduled(cron = "0 00 13* * *")
public void resetVotes() throws InterruptedException {
List<User> userArray = repository.findAll();
for(User user: userArray ) {
user.setVoted(false);
}
}
And this is the message I get on the console when I arrive at the time I determined in #Scheduled
Hibernate:
select
user0_.id as id1_1_,
user0_.email as email2_1_,
user0_.password as password3_1_,
user0_.name as name4_1_,
user0_.voted as voted5_1_
from
db_users user0_
Here are the classes I'm using for the project:
User.java
package com.dbserver.restaurantes.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "db_users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "Name")
private String username;
private String email;
private String password;
private Boolean voted = false;
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;
}
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 Boolean getVoted() {
return voted;
}
public void setVoted(Boolean voted) {
this.voted = voted;
}
}
UserDTO.java
package com.dbserver.restaurantes.dto;
import com.dbserver.restaurantes.entities.User;
public class UserDTO {
private Long id;
private String username;
private String email;
private String password;
private Boolean voted = false;
public UserDTO() {
}
public UserDTO(Long id, String username, String email, String password, Boolean voted) {
this.id = id;
this.username = username;
this.email = email;
this.password = password;
this.voted = voted;
}
public UserDTO(User user) {
id = user.getId();
username = user.getUsername();
email = user.getEmail();
password = user.getPassword();
voted = user.getVoted();
}
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;
}
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 Boolean getVoted() {
return voted;
}
public void setVoted(Boolean voted) {
this.voted = voted;
}
}
UserServices.java
package com.dbserver.restaurantes.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.dbserver.restaurantes.entities.User;
import com.dbserver.restaurantes.exceptions.HttpClientErrorException;
import com.dbserver.restaurantes.repositories.UserRepository;
#Service
public class UserServices {
#Autowired
private UserRepository repository;
PasswordEncoder passwordEncoder;
public UserServices(UserRepository userRepository) {
this.passwordEncoder = new BCryptPasswordEncoder();
}
#SuppressWarnings("rawtypes")
#Transactional(readOnly = true)
public List<User> findAllUsers(List list) {
List<User> result = repository.findAll();
return result;
}
#Transactional
public User addUser(User newUser) {
if (repository.findByEmail(newUser.getEmail()) != null) {
throw new HttpClientErrorException("O e-mail informado já existe no sistema");
}
String encodedPassword = this.passwordEncoder.encode(newUser.getPassword());
newUser.setPassword(encodedPassword);
return repository.saveAndFlush(newUser);
}
#Scheduled(cron = "0 00 13* * *")
public void resetVotes() throws InterruptedException {
List<User> userArray = repository.findAll();
for(User user: userArray ) {
user.setVoted(false);
}
}
}
UserRepository.java
package com.dbserver.restaurantes.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import com.dbserver.restaurantes.entities.User;
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
}
UserController.java
package com.dbserver.restaurantes.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.dbserver.restaurantes.entities.User;
import com.dbserver.restaurantes.services.UserServices;
#RestController
#RequestMapping(value = "/users")
public class UserController {
#Autowired
private UserServices service;
#PostMapping
public User addUser(#RequestBody User newUser) {
return service.addUser(newUser);
}
}
I think you need to re-update the user list after setVoted(false)
#Scheduled(cron = "0 00 13* * *")
public void resetVotes() throws InterruptedException {
List<User> userArray = repository.findAll();
for(User user: userArray ) {
user.setVoted(false);
}
repository.save(userArray);
}
You dont need to load all user from db.
You can just update data by a custom query.
#Scheduled(cron = "0 00 13* * *")
public void resetVotes() throws InterruptedException {
repository.resetVotes();
}
UserRepository.java
package com.dbserver.restaurantes.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.dbserver.restaurantes.entities.User;
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
//update custom query
#Modifying
#Query("update User set voted=false ")
int resetVotes();
}
I'm trying to sort of login with JPA and hibernate. The truth is that I'm new to working with hibernate and I don't know what I'm doing wrong.
I have two entity classes (User and Credential), and I have already mapped them in the persistence.xml file
<!-- Define Persistence Unit -->
<persistence-unit name="HibernateSchedule" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>ues.edu.sv.entity.User</class>
<class>ues.edu.sv.entity.Credential</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/diary?useSSL=false&useTimezone=true&serverTimezon=UTC&allowPublicKeyRetrieval=true"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="localhost"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
</properties>
</persistence-unit>
These are the entity classes:
package ues.edu.sv.entity;
import java.io.Serializable;
import javax.persistence.*;
#Entity
#NamedQueries({
#NamedQuery(name="User.listAllUsers", query="SELECT u FROM User u")
})
#Table(name = "\"user\"")
public class User implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id_user")
private int idUser;
private String name;
#Column(name = "lastname")
private String lastName;
private String email;
public User(){}
public User(int idUser){
this.idUser = idUser;
}
public User(String name, String lastName, String email){
this.name = name;
this.lastName = lastName;
this.email = email;
}
public User(int idUser, String name, String lastName, String email){
this.idUser = idUser;
this.name = name;
this.lastName = lastName;
this.email = email;
}
public int getIdUser() {
return idUser;
}
public void setIdUser(int idUser) {
this.idUser = idUser;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Override
public String toString() {
return "User{" + "idUser=" + idUser + ", name=" + name + ", lastName=" + lastName + ", email=" + email + '}';
}
}
This is the Credential class
package ues.edu.sv.entity;
import java.io.Serializable;
import javax.persistence.*;
#Entity
#NamedQueries({
#NamedQuery(name = "Credential.getAllCredentials", query = "SELECT c FROM Credential
c")
})
#Table(name = "credential")
public class Credential implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id_credential")
private int idCredential;
#Column(name = "username")
private String userName;
private String password;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "id_user", referencedColumnName = "id_user")
private User user;
public Credential(){}
public Credential(int idCredential){
this.idCredential = idCredential;
}
public Credential(String userName, String password){
this.userName = userName;
this.password = password;
}
public Credential(String userName, String password, User user){
this.userName = userName;
this.password = password;
this.user = user;
}
public Credential(int idCredential,String userName, String password){
this.idCredential = idCredential;
this.userName = userName;
this.password = password;
}
public int getIdCredential() {
return idCredential;
}
public void setIdCredential(int idCredential) {
this.idCredential = idCredential;
}
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;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#Override
public String toString() {
return "Credential{" + "idCredential=" + idCredential + ", userName=" + userName + ", password=" + password + ", user=" + user + '}';
}
}
I am using a three layer pattern to retrieve the information, so I have a package "ues.edu.sv.dao" where I have two interfaces and two classes that implement them and are defined as ejb
package ues.edu.sv.dao;
import java.util.List;
import ues.edu.sv.entity.User;
public interface UserDao {
public List<User> listAllUsers();
public User getUserById(User user);
public void createNewUser(User user);
public void updateUser(User user);
public void deleteUser(User user);
}
package ues.edu.sv.dao;
import java.util.List;
import ues.edu.sv.entity.Credential;
public interface CredentialDao {
public List<Credential> getAllCredentials();
public Credential getCredentialById(Credential credential);
public Credential getCredentialByUserName(Credential credential);
public void createNewCredential(Credential credential);
public void updateCredential(Credential credential);
public void deleteCredential(Credential credential);
}
And here are the classes that implement their corresponding interface
package ues.edu.sv.dao;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.*;
import ues.edu.sv.entity.User;
#Stateless
public class UserDaoImpl implements UserDao {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("HibernateSchedule");
EntityManager em = emf.createEntityManager();
#Override
public List<User> listAllUsers() {
return em.createNamedQuery("User.listAllUsers").getResultList();
}
#Override
public User getUserById(User user) {
return em.find(User.class, user.getIdUser());
}
#Override
public void createNewUser(User user) {
em.persist(user);
}
#Override
public void updateUser(User user) {
em.merge(user);
}
#Override
public void deleteUser(User user) {
em.remove(em.merge(user));
}
}
package ues.edu.sv.dao;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import ues.edu.sv.entity.Credential;
#Stateless
public class CredentialDaoImpl implements CredentialDao {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("HibernateSchedule");
EntityManager em = emf.createEntityManager();
#Override
public List<Credential> getAllCredentials() {
return em.createNamedQuery("Credential.getAllCredentials").getResultList();
}
#Override
public Credential getCredentialById(Credential credential) {
return em.find(Credential.class, credential.getIdCredential());
}
#Override
public Credential getCredentialByUserName(Credential credential) {
return em.find(Credential.class, credential.getUserName());
}
#Override
public void createNewCredential(Credential credential) {
em.persist(credential);
}
#Override
public void updateCredential(Credential credential) {
em.merge(credential);
}
#Override
public void deleteCredential(Credential credential) {
em.remove(em.merge(credential));
}
}
My understanding is that since I am working in a java enterprise context, there is no need to open a transaction when persisting an object in the database. I am using glassfish by the way.
now to complete the three-layer pattern, I have another package called "ues.edu.sv.service" that injects the above interfaces via CDI
package ues.edu.sv.service;
import java.util.List;
import javax.ejb.Local;
import ues.edu.sv.entity.Credential;
#Local
public interface CredentialService {
public List<Credential> getAllCredentials();
public Credential getCredentialById(Credential credential);
public Credential getCredentialByUserName(Credential credential);
public void createNewCredential(Credential credential);
public void updateCredential(Credential credential);
public void deleteCredential(Credential credential);
}
package ues.edu.sv.service;
import java.util.List;
import javax.ejb.Local;
import ues.edu.sv.entity.User;
#Local
public interface UserService {
public List<User> listAllUsers();
public User getUserById(User user);
public void createNewUser(User user);
public void updateUser(User user);
public void deleteUser(User user);
}
and implementation classes
package ues.edu.sv.service;
import java.util.List;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.inject.Inject;
import ues.edu.sv.dao.CredentialDao;
import ues.edu.sv.entity.Credential;
#Stateless
public class CredentialServiceImpl implements CredentialService{
#Inject
CredentialDao credentialDao;
#Resource
SessionContext context;
#Override
public List<Credential> getAllCredentials() {
return credentialDao.getAllCredentials();
}
#Override
public Credential getCredentialById(Credential credential) {
return credentialDao.getCredentialById(credential);
}
#Override
public Credential getCredentialByUserName(Credential credential) {
return credentialDao.getCredentialByUserName(credential);
}
#Override
public void createNewCredential(Credential credential) {
credentialDao.createNewCredential(credential);
}
#Override
public void updateCredential(Credential credential) {
try{
credentialDao.updateCredential(credential);
}catch(Exception ex){
ex.printStackTrace(System.out);
context.setRollbackOnly();
}
}
#Override
public void deleteCredential(Credential credential) {
credentialDao.deleteCredential(credential);
}
}
package ues.edu.sv.service;
import java.util.List;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.inject.Inject;
import ues.edu.sv.dao.UserDao;
import ues.edu.sv.entity.User;
#Stateless
public class UserServiceImpl implements UserService{
#Inject
UserDao userDao;
#Resource
SessionContext context;
#Override
public List<User> listAllUsers() {
return userDao.listAllUsers();
}
#Override
public User getUserById(User user) {
return userDao.getUserById(user);
}
#Override
public void createNewUser(User user) {
userDao.createNewUser(user);
}
#Override
public void updateUser(User user) {
try{
userDao.updateUser(user);
}catch(Exception ex){
ex.printStackTrace(System.out);
context.setRollbackOnly();
}
}
#Override
public void deleteUser(User user) {
userDao.deleteUser(user);
}
}
And finally I have an ejb that connects to the jsf page called "Register.xhtml" and is responsible for retrieving the information that the user enters in the text fields to finally persist the information in the database, I have programmed the relationships so cascading user object can be persisted
package ues.edu.sv.beans;
import java.io.IOException;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import ues.edu.sv.crypto.Cypher;
import ues.edu.sv.entity.Credential;
import ues.edu.sv.entity.User;
import ues.edu.sv.service.CredentialService;
import ues.edu.sv.service.UserService;
#Named
#RequestScoped
public class RegisterBean {
#Inject
CredentialService credentialService;
#Inject
UserService userService;
private String name;
private String lastName;
private String email;
private String userName;
private String password;
public RegisterBean() {
}
public void toRegister() {
User user = new User(name, lastName, email);
String encriptedPassword = Cypher.encryptPassword(password);
Credential credential = new Credential(userName, encriptedPassword, user);
credentialService.createNewCredential(credential);
try {
FacesContext.getCurrentInstance().getExternalContext().redirect("Login.xhtml");
} catch (IOException ex) {
ex.printStackTrace(System.out);
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
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;
}
}
And apparently everything is fine, the console does not show me any error, but it does nothing in the database, it does not insert the content into the database :(
This is what appears in the console when everything has been executed...
]|#]
HHH000204: Processing PersistenceUnitInfo [name: HibernateSchedule]|#]
HHH000412: Hibernate Core {6.0.0.Alpha4}|#]
HCANN000001: Hibernate Commons Annotations {5.1.0.Final}|#]
HHH10001002: Using Hibernate built-in connection pool (not for production use!)|#]
HHH10001005: using driver [com.mysql.cj.jdbc.Driver] at URL
[jdbc:mysql://localhost:3306/diary?
useSSL=false&useTimezone=true&serverTimezon=UTC&allowPublicKeyRetrieval=true]|#]
HHH10001001: Connection properties: {user=root, password=****}|#]
HHH10001003: Autocommit mode: false|#]
HHH000115: Hibernate connection pool size: 20 (min=1)|#]
HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect|#]
HHH10005002: No explicit CDI BeanManager reference was passed to Hibernate, but CDI
is available on the Hibernate ClassLoader.|#]
HHH000490: Using JtaPlatform implementation:
[org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]|#]
That is all that appears. Someone who can help me please
Hi all I´m learning how to use Spring, I don´t have experience in MVC.
So I´m making a website who makes registrations, de-registrations and changes in the data of a mysql database.
The login and inserts to DB are ready but I can't make the delete registered user part.
My model:
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
public class StudentDelete {
#NotEmpty
#Size(min=4, max=20)
private String userName;
#NotEmpty
#Size(min=4, max=8)
private String password;
public String getPassword() {
return password;
}
public String getUserName() {
return userName;
}
public void setPassword(String password) {
this.password = password;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
My Controller:
#Controller
#SessionAttributes("student")
public class StudentController {
#Autowired
private StudentService studentService;
#RequestMapping(value="/delete", method=RequestMethod.GET)
public String delete(Model model) {
Student studentDelete = new Student();
model.addAttribute("studentDelete", studentDelete);
return "delete";
}
blablabla
#RequestMapping(value="/delete", method=RequestMethod.POST)
public String delete(#Valid #ModelAttribute("studentDelete") StudentDelete studentDelete, BindingResult result) {
if (result.hasErrors()) {
return "delete";
} else {
boolean found = studentService.findByLogin(studentDelete.getUserName(), studentDelete.getPassword());
if (found) {
studentService.deleteByLogin(studentDelete.getUserName(), studentDelete.getPassword());
return "successD";
} else {
return "failureD";
}
}
}
My Service and the implementation:
package com.github.elizabetht.service;
import com.github.elizabetht.model.Student;
public interface StudentService {
Student save(Student student);
boolean findByLogin(String userName, String password);
boolean findByUserName(String userName);
boolean deleteByLogin(String userName, String password);
}
Implementation:
public boolean deleteByLogin(String userName, String password) {
StudentDelete stud = studentDeleteRepository.deleteByLogin(userName, password);
if(stud != null) {
return true;
}
return false;
}
And finally The StudentDeleteRepository:
package com.github.elizabetht.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.github.elizabetht.model.Student;
import com.github.elizabetht.model.StudentDelete;
#Repository("studentDeleteRepository")
public interface StudentDeleteRepository extends JpaRepository<StudentDelete, Long> {
#Query("delete s from Student s where s.userName = :userName and s.password = :password")
StudentDelete deleteByLogin(#Param("userName") String userName, #Param("password") String password);
}
StudentRepository.java
package com.github.elizabetht.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.github.elizabetht.model.Student;
#Repository("studentRepository")
public interface StudentRepository extends JpaRepository<Student, Long> {
#Query("select s from Student s where s.userName = :userName")
Student findByUserName(#Param("userName") String userName);
}
In my delete.jsp all starts with this:
<form:form id="myForm" method="post"
class="bs-example form-horizontal" commandName="studentDelete">
I'm getting this error:
java.lang.NullPointerException
com.github.elizabetht.service.StudentServiceImpl.deleteByLogin(StudentServiceImpl.java:47)
Which is this part:
StudentDelete stud = studentDeleteRepository.deleteByLogin(userName, password);
Why it doesnt happen with the save method?
Any help is appreciated.
Thanks!
Your issue is that parameter you are passing below:
StudentDelete stud = studentDeleteRepository.deleteByLogin(userName, password);
username or password are empty.
Hence the null pointer exception.
Change your implementation to following formate:
public boolean deleteByLogin(String userName, String password) {
if(userName == null || password == null)
return false; // it failed essentially
StudentDelete stud = studentDeleteRepository.deleteByLogin(userName, password);
if(stud != null) {
return true;
}
return false;
}
I think the error you specified in the comments:
Not a managed type: class com.github.elizabetht.model.StudentDelete
is because you are missing the JPA #Entity annotation on your model class:
import javax.validation.constraints.Size;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.hibernate.validator.constraints.NotEmpty;
#Entity
#Table("student")
public class StudentDelete {
#NotEmpty
#Size(min=4, max=20)
private String userName;
#NotEmpty
#Size(min=4, max=8)
private String password;
public String getPassword() {
return password;
}
public String getUserName() {
return userName;
}
public void setPassword(String password) {
this.password = password;
}
public void setUserName(String userName) {
this.userName = userName;
}
}