How to join two tables in spring hibernate? - spring

I have a web application which uses spring hibernate technology. I have role based accesss control wherein user may have specific roles to access the system. Each user may be assigned to multiple roles. Roles are assigned with multiple permissions. My table structure is given below.
role_permission(role_perm_id(PK), role_id(FK), screen_perm_id(FK))
role(role_od(PK),role_name))
screen_perm(screen_perm_id(PK), screen_id(FK), perm_id(FK))
screens(screen_id(PK), screen_name)
permission(perm_id(PK),perm_name)
I want to have a view page which displays all permissions of a role. In that page i want to have a checkbox which shows permission. If that permissions is assigned to role then it is checked and if it is not assigned then it is unchecked. How van i do it. Im new to spring hibernate. Pleasw help.

public class Role{
#OneToMany(
mappedBy = "role",
cascade = CascadeType.ALL,
orphanRemoval = true)
Set<Permission> permissions= new HashSet<>();
}
public class Permission {
#ManyToOne(fetch = FetchType.LAZY)
Role role;
}
And then you can get the permissions with role.getPermissions();

Related

Spring, Question regarding Query on Many-to-Many(Association with Extra Columns) in web development

I have 3 class that using Many to Many relationship in Entity level (herbibate)
They are Teams,Users and TeamUsers.
Since I am using hibernate they are all Fetch Lazy
Team:
Users:
TeamUsers:
and we have 3 interface (using by #Autowired in Service or repo layer) which is:
1.TeamRepository extends PagingAndSortingRepository<Team, Integer>
2.UserRepository extends PagingAndSortingRepository<User, Integer>
3.TeamUserRepository extends PagingAndSortingRepository<TeamUsers, Integer>
And here is the core code for many to many relationship mapping:
Team class:
#OneToMany(mappedBy = "team", fetch = FetchType.EAGER)
private Set<TeamUsers> team_users = new HashSet<TeamUsers>();
User class:
#OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
private Set<TeamUsers> team_users = new HashSet<TeamUsers>();
TeamUsers class:
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "TEAM_ID")
private Team team;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "USER_ID")
private User user;
Now, my questions is, what is the best practice to play around this data?
for example:
1. I need all team information and team member from my DB
In restful controller get mapping function, what should I return? should I use TeamUser repository (or maybe one more service layer) to return findAll()? if do so the data will come as object collection of User and Team right(maybe also contain extra column in that table)? Can Json successfully contain that data?
2. I am on webpage and I want to delete a user from a team.
At this timepoint I know the TeamID and UserID from HTML, when I send the Post request to API, should I get User object by UserID, then get Team object by TeamID, then get(Query) TeamUsers object by giving User object and Team Object? or maybe just query by id(from TeamUsers on html) send to API and simply remove this TeamUsers entity?
I'm new to spring and frontend development and I am much apprecaite for your help!
I would suggest the following
If you want to return all the teams and for each team all its users, you should have a TeamService which call findAll method of Team repository this way you will get a list of Teams and for each team a set with its users. And if instead of that you want all of your users and for each one what are its teams you should do the other way, call the findAll method of User repository
Both solutions will serialize to json without problem as long as the objects have its constructor and getter and setter methods
If you want to delete only the relation between user and team you could have a method in your TeamEntity Spring Data repository like this
long deleteByTeamIdAndUserId(long teamId, long userId);
And spring will create a method to perform this action or you can write the query you like just above the method name to be more specific
#Modifying
#Query("delete from TeamUsers t where t.userId=:userId and t.teamId = :teamId")
long deleteByTeamIdAndUserId(long teamId, long userId);

Entity is not being created on database when JoinColumn annotation is added

I have this model class:
public class Usuario {
...
#OneToMany(fetch = FetchType.EAGER)
#Fetch(FetchMode.SELECT)
private List<org.loja.model.credencial.Credencial> credenciais;
...
}
If I add this annotation to this attribute:
#JoinColumn(unique=false)
causes the table usuario_credenciais not being created on database (it is when the annotation is omitted, but causes problems during runtime due to the uniqueness situation).
What I can do to solve that?
I solve that changing the OneToMany annotation to ManyToOne, getting this:
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name="usuario_credenciais", joinColumns={#JoinColumn(name="usuario_id")}, inverseJoinColumns={#JoinColumn(name="credencial_id")})
#Fetch(FetchMode.SELECT)
private List<org.loja.model.credencial.Credencial> credenciais;
Now the table is created on the database, and the application allows multiple users have the same credentials.

architecture microservice spring boot

I am working with Spring cloud (microservices) and I have implemented security with JWT token.
in my security application, I have entities like User, Role and UserRole.
so Every request first comes to the ZOOL service and it calls Authentication service and Authentication service creates/returns JWT token.
Also, I have another microservice-rest application (Questions-app) that needs JWT token.
in the Questions-app I have a Question entity that contains authorId field.
#Entity
#Table(name="QUESTION")
public class Question {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID", updatable = false, nullable = false)
private long id;
#Column(name = "AUTHOR")
private long authorId;
#Column(name = "TITLE")
private String title;
}
Now, it is not clear for me, is it right to set authorId long type or I should create User, Role, UserRole entities (just simple copy from AUTH project) in the questions-app and set "AUTHOR" column like that
#OneToOne
#JoinColumn(name="AUTHOR")
private User user;
I know that in the first option when I need show question and user's name on the webpage, then I should call 2 services (one from question-app (fetch question) and another from auth service (fetch user information by author id)
I would like to know what is the best practises?
If you have common database for all of these microservices and you need User related information based on question id.
Then instead of doing another database call for user, you can directly do #OneToOne to User.
From your question it is better to go for 2 option.

Spring Boot many to many post method not updating data

My User class looks like this :
#Data
#Entity
public class User {
#Id
Long userID;
#ManyToMany(mappedBy = "admins")
private List<ClassRoom> classRooms = new ArrayList<>();
}
And my ClassRoom class like this :
#Data
#Entity
public class ClassRoom {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long classRoomID;
#ManyToMany
#JoinTable(name ="classroom_user",
joinColumns = #JoinColumn(name = "classroom_id"),
inverseJoinColumns = #JoinColumn(name = "user_id"))
private List<User> admins = new ArrayList<>();
}
And in my UserController class, I have :
#PostMapping("user/{id}/c")
User addClassRoom(#PathVariable Long id,#RequestBody ClassRoom newClassRoom)
{
logger.debug(repository.findById(id));
return repository.findById(id)
.map(user -> {
user.getClassRooms().add(newClassRoom);
user.setClassRooms(user.getClassRooms());
return repository.save(user);
})
.orElseGet(() -> {
return null;
});
}
And I POST and empty JSON ({}) and I see no change in my users. The Classroom or an empty Classroom doesn't get added in the User.
What is the problem here? How can I resolve this ?
user.getClassRooms().add(newClassRoom); is suffice, user.setClassRooms(user.getClassRooms()); not required.
You will have to perform cascade save operation.List all cascade types explicitly and don't use mappedBy, instead use joincolumns annotation.
Can you paste the logs, please? Is Hibernate doing any insert into your table? Has the database schema been created in the DB correctly? One thing I recommend you to do is to add a custom table name on the top of your User class, using annotations like so: #Table(name = "users"). In most SQL dialects user is a reserved keyword, hence it is recommended to always annotate User class a bit differently, so that Hibernate won't have any problems to create a table for that entity.
IMO you must find classRoom by its id from repository, if it's new, you must create a new entity and save it first. Then assign it to user and save it.
The object you receive from the post method was not created by the entity manager.
After using user.getClassRooms().add(newClassRoom);
We must use userRepository.save(user);

Authorize Object using spring security?

I have an application that have two domain model
Organization and TicketQuestion .
Authenticated User want to create ticket that have an organization property to solve that
each user permit to some organization like this:
User1 permit to Organization1
User2 permit to Organization2
TicketController.java have save method that create ticket.
I have this vulnerability: User1 can invoke method with ticket that have Organization2( that dose not have permission to it ).
I am using Hibernate filter for authorize data in GET methods but i dont know how can i protect data that user want persist and dose not have permission ??;
/ticket/save
{
id:-1,
organization:{
id:2,
title:'organization2' //not allowed this organization
}
}
#Entity
#Table(name = "core_organization_structure")
public class OrganizationStructure {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "title", nullable = false)
private String title;
}
#Entity
#Table(name = "core_Ticket")
public class Ticket {
..some prop
#ManyToOne
#JoinColumn(name = "org_id", nullable = false)
private OrganizationStructure org;
}
When the form is submitted, you need to load the authenticated user's permissions and check that they are authorized to perform the action they are attempting to perform.
If the user is attempting to create a ticket for an organization that they do not have permissions to; don't persist the record, and handle it appropriately. (Throw an exception, return a 401, etc...)

Resources