I've a User entity.
public class User {
private String username;
private String password;
private String firstname;
private String lastname;
/* Other user attributes */
/* Getters and Setters */
}r
I need to send this user to view layer to display user info but I don't want password field to be sent to view layer for security concerns.
Currenlty, I am not using DTOs.
How can I omit password field while retrieving User entity from database?
Basically, how can I filter password field from User entity while sending to view layer?
My application is built with spring-data-jpa and spring-mvc.
You may want to use JPA-Projections Example . Spring may have similar feature..
Related
I am using multiple aggregate roots inside a DDD bounded context.
For example
public class OrderAggregate
{
public int ID {get;set;}
public string Order_Name {get;set;}
public int Created_By_UserID {get;set;}
}
public class UserAggregate
{
public int ID {get;set;}
public string Username {get;set;}
public string First_Name {get;set;}
public string Last_Name {get;set;}
}
I am using SQL relational base to persists domain objects. Each aggregate root matches one repository.
In case I would like to find an order that was created by John Doe (seach accross multiple aggregates) what would be a DDD way to go?
add First_Name and Last_Name into OrderAggregate in order to add FindByUserFirstLastName method in OrderRespository, but that could raise data consistency issue between two aggregate roots
create a raw sql query and access DB directly in order to span search accross "repositories"
use "finders" in order to join entities directly from DB
replicate data necessary for query to be completed to a new aggregate root such as
public class QueryOrderAggregate
{
public int ID { get; set; }
public string Order_Name { get; set; }
public int Created_By_UserID { get; set; }
public string First_Name { get; set; }
public string Last_Name { get; set; }
}
In case I would like to find an order that was created by John Doe (seach accross multiple aggregates) what would be a DDD way to go?
Almost the same way that it goes with accessing an aggregate...
You create a Repository that provides a (whatever the name for this view/report is in your domain). It probably uses the UserId as the key to identify the report. In the implementation of the repository, the implementation can do whatever makes sense -- a SQL join is a reasonable starting point.
The View/Report is basically a value type; it is immutable, and can provide data, but doesn't not have any methods, or any direct access to the aggregate roots. For example, the view might include the OrderId, but to actually get at the order aggregate root you would have to invoke a method on that repository.
A view that spans multiple aggregates is perfectly acceptable, because you can't actually modify anything using the view. Changes to the underlying state still go through the aggregate roots, which provide the consistency guarantees.
The view is a representation of a stale snapshot of your data. Consumers should not be expecting it to magically update -- if you want something more recent, go back to the repository for a new copy.
I want to add new field description to User entity. I can't use yo jhipster:entity User because it is forbidden. So, what I have to do?
If we need to store more information concerning a user than what JHipster provides by default, a few tweaks are needed.
To illustrate this, let’s assume we want to store the user’s phone number.
Creating a new entity in a One to One relationship with JHI_User
The best way to add information that is not handled by the default JHipster User is by using composition in a new entity linked to it with a One to One relationship.
After this entity is created, let’s call it UserExtra, the best way to handle its id is by mapping it to the JHI_User’s one. This way, our UserExtra will have the same id as the User’s, accelerating the different requests. To achieve this, you will need to use the #MapsId annotation :
public class UserExtra implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Long id;
#Column(name = "phone")
private String phone;
#OneToOne
#MapsId
private User user;
...
}
Note that the #GeneratedValue annotation on the id needs to be removed.
Updating the register HTML page to take this change into account
Now that an entity exists to store the phone number, we need to add an input in the register form to ask for the user’s phone number.
Nothing easier than that, just update webapp/app/account/register/register.html to add an input field bound to the variable already used to store the basic information (vm.registerAccount) :
<input class="form-control" id="phone" ng-model="vm.registerAccount.phone" placeholder="global.form.phone.placeholder" />
Updating ManagedUserVM
The registerAccount() function from java/com.mycompany.myapp/web/rest/AccountResource is the one receiving the request from the registration page. Its only parameter is a ManagedUserVM object containing the information initially contained in the vm.registerAccount variable from the client.
This ManagedUserVM class located in web/rest/vm has to be updated as well so that it holds the phone number sent by the client. The only thing to do here is adding the phone number attribute and its getter :
public class ManagedUserVM extends UserDTO {
// Default attributes omitted for brevity
private String phone;
...
public String getPhone() {
return phone;
}
}
Updating the registerAccount() function from AccountResource
The registerAccount() function now receives a ManagedUserVM object that also contains the phone number of the user. The only thing left to do is saving this phone number into a new UserExtra associated with the JHipster User.
To do so, we are going to add the phone parameter to the createUser() function from UserService. But first, add this parameter where this function is called in registerAccount() :
public ResponseEntity<?> registerAccount(#Valid #RequestBody ManagedUserVM managedUserVM) {
HttpHeaders textPlainHeaders = new HttpHeaders();
textPlainHeaders.setContentType(MediaType.TEXT_PLAIN);
return userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase())
.map(user -> new ResponseEntity<>("login already in use", textPlainHeaders, HttpStatus.BAD_REQUEST))
.orElseGet(() -> userRepository.findOneByEmail(managedUserVM.getEmail())
.map(user -> new ResponseEntity<>("e-mail address already in use", textPlainHeaders, HttpStatus.BAD_REQUEST))
.orElseGet(() -> {
User user = userService
.createUser(managedUserVM.getLogin(), managedUserVM.getPassword(),
managedUserVM.getFirstName(), managedUserVM.getLastName(),
managedUserVM.getEmail().toLowerCase(), managedUserVM.getLangKey(),
managedUserVM.getPhone());
mailService.sendActivationEmail(user);
return new ResponseEntity<>(HttpStatus.CREATED);
})
);
}
Updating the createUser() function from UserService
Finally, we update the service layer function that saves the JHI_User to now save the UserExtra as well. Rather than updating the existing function, I suggest you create a new one with the additional parameter. This way, updating the test classes isn’t necessary.
Do not forget to inject the UserExtra repositories :
#Inject
private UserExtraRepository userExtraRepository;
#Inject
private UserExtraSearchRepository userExtraSearchRepository;
...
public User createUser(String login, String password, String firstName, String lastName, String email,
String langKey, String phone) {
User newUser = new User();
Authority authority = authorityRepository.findOne(AuthoritiesConstants.USER);
Set<Authority> authorities = new HashSet<>();
String encryptedPassword = passwordEncoder.encode(password);
newUser.setLogin(login);
// new user gets initially a generated password
newUser.setPassword(encryptedPassword);
newUser.setFirstName(firstName);
newUser.setLastName(lastName);
newUser.setEmail(email);
newUser.setLangKey(langKey);
// new user is not active
newUser.setActivated(false);
// new user gets registration key
newUser.setActivationKey(RandomUtil.generateActivationKey());
authorities.add(authority);
newUser.setAuthorities(authorities);
userRepository.save(newUser);
userSearchRepository.save(newUser);
log.debug("Created Information for User: {}", newUser);
// Create and save the UserExtra entity
UserExtra newUserExtra = new UserExtra();
newUserExtra.setUser(newUser);
newUserExtra.setPhone(phone);
userExtraRepository.save(newUserExtra);
userExtraSearchRepository.save(newUserExtra);
log.debug("Created Information for UserExtra: {}", newUserExtra);
return newUser;
}
https://jhipster.github.io/tips/022_tip_registering_user_with_additional_information.html
Add column to entity User.java:
#Column(name = "description")
private String description;
Modify method toString().
In UserDTO.java add:
private String description;
Generate getter and modify method toString().
Add liquidbase diff or add column.
Now is time to modify some webapp folder.
File user-managment.state.js find state user-managment.new and to entity: function () new return ,description: null
If you want to add this field to display find and modify files:
user-managment.html
user-managment-detail.html
user-managment-dialog.html
For example: <th><span data-translate="some.some.user.description">Description</span></th>
I need to display a large table with about 1300 roles at one time. (I know I should use a data scroll but my users want to see the whole table at one time.) The table displays 4 columns. Two of those columns are from the object but the other two are from referenced objects in the original object. I need to find the best/efficient way to do this. I currently have this working but when I reload the table it give an out of memory error. I think that it's caused by the large amount of redundant data in memory.
Create a view object that the repository will fill in only the needed fields.
Any other suggestions.
Here are the objects:
public class Database extends EntityObject {
private Long id;
private String name;
private String connectionString;
private String username;
private String password;
private String description;
// getter and setters omitted
}
public class Application extends EntityObject {
private Long id;
private String name;
private String fullName = "";
private String description;
private Database database;
private List<Role> roles = new ArrayList<Role>(0);
// getter and setters omitted
}
public class Role extends EntityObject {
private Long id;
private String name;
private String nameOnDatabase;
private Application application;
// getter and setters omitted
}
What I need displayed from the list of Roles is:
role.id, role.name, role.application.name, role.application.database.name
To optimize wisely, define what are you going to do with data, view or/and edit. Here are some common scenarios:
Retrieval using lazy fetch type.
Mark your roles in application with FetchType.LAZY annotation.
Retrieval using multiselect query. Create your custom class (like DTO) and populate it with data from the database using multiselect query. (Similar to VIEW mapped as Entity)
There are also other possibilities, such as Shared (L2) Entity Cache or Retrieval by Refresh.
See if you are using EntityManager correctly reading Am I supposed to call EntityManager.clear() often to avoid memory leaks?.
I was learning AutoMapper and understand its use for object to object mapping. But now EFCodeFirst,dapper and Petpoco all cools stuff are there which will allow us to use our POCO directly with database?
So can anybody let me know why we still need automapper?
Thanks in advance
Best Regards,
Jalpesh
I usually use Automapper to map Domain models to view mdoels. If doing DDD it is often suggested that it's not a great idea to use your Domain models in you views - views often have a different set of concerns to the domain.
For example, you may have a User model in your domain:
public class User
{
public int Id {get;set;}
public string EmailAddress {get;set;}
public string FirstName {get;set;}
public string Surname {get;set;}
public string HashedPassword {get;set;}
public string EyeColour {get;set;}
}
And you may have a User summary page which shows a subset of these items:
public class UserSummary
{
public string EmailAddress {get;set;}
public string Surname {get;set;}
}
You could use the UserSummary class on the view, but you would probably fetch the domain user model from the db. In this case you could use Automapper to map the Domain.User to the ViewModel.UserSummary
var user = _repository.Get(1);
var viewmodel = Automapper.Map<Domain.User, ViewModel.UserSummary>(user);
return View(viewmodel);
In my JSF web application, I use EclipseLink
Descriptor Customizer
and
History Policy
to populate a history table in database.
The corresponding JPA entity class is annotated with #Customizer(beans.HistoryLesionhCustomizer.class)
The history table has the same fields as the source table, plus two fields (start_date & end_date) to specify the start and end of operation on a row.
It is fully working. But what I need is to populate another field in the history table.
This field I called user, should be populated with the User Principals, and this will allow me to trace the user who performed the CUD (Create/Update/Delete) operation.
I thought History Policy would allow me to add a field by just indicating its corresponding name in the database and indicate the object value that must be inserted. But that is not the case, or may it be I am not able to figure how this can be done.
In other words, along with start_date and end_date, i want to populate user field with :
FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();
package beans;
/**
* Whenever there is a change on a record or an insert, change will be traced.
* #author mediterran
*
*/
import javax.faces.context.FacesContext;
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.history.HistoryPolicy;
public class HistoryLesionhCustomizer implements DescriptorCustomizer {
#Override
/**
* Implementation method to use
*/
public void customize(ClassDescriptor cd) throws Exception {
String user = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();
HistoryPolicy policy = new HistoryPolicy(); // Instantiates a new policy
//policy.postUpdate();
policy.useDatabaseTime(); // Use the default database time to avoid date conflict
policy.addHistoryTableName("history_lesionh"); // Indicate the source table name
policy.addStartFieldName("start_date"); // indicate the start date DB column
policy.addEndFieldName("end_date"); // Indicate the end date DB column
cd.setHistoryPolicy(policy); // Use the Policy for the entity class where used #Customizer(HistoryLesionhCustomizer.class)
}
}
Any help or workarounds would be appreciated.
Thanks
Unfortunately HistoryPolicy only adds start and end date. But you can add user information to your entity with the help of an EntityListeners . Here is an example. It will add user information to each persist/update of the customer table:
import javax.persistence.EntityListeners;
#Entity
#EntityListeners(AuditListener.class)
#Table(name = "customer")
public class Customer implements Serializable {
#Column(name = "User")
private String user;
// getter and setter
}
and the AuditListener:
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
//...
public class AuditListener {
#PrePersist
#PreUpdate
public void setUserInformation(Object entity) {
if (entity instanceof Customer) {
Customer myEntity = (Customer) entity;
myEntity.setUser(FacesContext.getCurrentInstance().getExternalContext().getRemoteUser());
}
}
}
If you have more than one column that needs user information, you can use a MappedSuperclass entity and put the user column in this class. Then let all your auditable entities extend this MappedSuperclass and check in the AuditListener if the entity is an instance of the superclass.