JHipster: user registration with additional information

First of all, I would like to thank Paul Etienne for his useful question and answer ! The answer below is a bit more detailed and was written taking into account the latest version of JHipster (3/17/2018).

The question is how to add a new data field to a custom object in a JHipster project.

+1
source share
1 answer

As mentioned on the official JHipster website, the best way to add new fields / relationships to the JHipster user by default is to create a new object and associate it with the user with a one-to-one relationship. You can handle more relationships in a new entity. Let me name this new entity UserExtra. Composition between User and UserExtra

The UML diagram above shows the composition between the user and UserExtra, meaning that the user has UserExtra, which is highly dependent on the user and cannot exist without the user. In other words, there must first be a user so that we can assign a phone number.

Step 1: Create a New Object

I suggest creating a new entity using terminal: jhipster entity userExtra

or

JDL:

enter image description here

Step 2: change the new object

You can find the new entity class in the domain folder: enter image description here

We can match the UserExtra ID with the user ID so that we can use the UserExtra ID as a foreign key. If so, then we should no longer use the @GeneratedValue annotation for the identifier in UserExtra. Here is an example of the UserExtra class. Here is an example of a modified UserExtra:

package org.jhipster.domain; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import javax.persistence.*; import java.io.Serializable; import java.util.Objects; /** * A UserExtra. */ @Entity @Table(name = "user_extra") @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) public class UserExtra implements Serializable { private static final long serialVersionUID = 1L; @Id private Long id; @OneToOne @MapsId private User user; @Column(name = "phone") private String phone; // jhipster-needle-entity-add-field - JHipster will add fields here, do not remove public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getPhone() { return phone; } public UserExtra phone(String phone) { this.phone = phone; return this; } public void setPhone(String phone) { this.phone = phone; } public User getUser() { return user; } public UserExtra user(User user) { this.user = user; return this; } public void setUser(User user) { this.user = user; } // jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } UserExtra userExtra = (UserExtra) o; if (userExtra.getId() == null || getId() == null) { return false; } return Objects.equals(getId(), userExtra.getId()); } @Override public int hashCode() { return Objects.hashCode(getId()); } @Override public String toString() { return "UserExtra{" + "id=" + getId() + ", phone='" + getPhone() + "'" + "}"; } } 

Step 3: Change the configuration of the new object

[You can skip this step if you used JDL in the first step]

There is a json file storing the configuration of the object: enter image description here We need to change the configuration. Here is an example of a modified json configuration file:

 { "fluentMethods": true, "relationships": [ { "relationshipType": "one-to-one", "relationshipName": "user", "otherEntityName": "user", "otherEntityField": "id", "ownerSide": true, "otherEntityRelationshipName": "userExtra" } ], "fields": [ { "fieldName": "phone", "fieldType": "String" } ], "changelogDate": "20180317190851", "dto": "no", "service": "no", "entityTableName": "user_extra", "jpaMetamodelFiltering": false, "pagination": "no" } 

There are also some XML change logs: enter image description here Here are examples of change logs:

added_entity_UserExtra:

 <?xml version="1.0" encoding="utf-8"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd"> <property name="now" value="now()" dbms="h2"/> <property name="now" value="now()" dbms="mysql"/> <!--<property name="autoIncrement" value="true"/>--> <property name="floatType" value="float4" dbms="postgresql, h2"/> <property name="floatType" value="float" dbms="mysql, oracle, mssql"/> <!-- Added the entity UserExtra. --> <changeSet id="20180317190851-1" author="jhipster"> <createTable tableName="user_extra"> <column name="user_id" type="bigint"> <constraints primaryKey="true" nullable="false"/> </column> <column name="phone" type="varchar(255)"> <constraints nullable="true" /> </column> <!-- jhipster-needle-liquibase-add-column - JHipster will add columns here, do not remove--> </createTable> </changeSet> <!-- jhipster-needle-liquibase-add-changeset - JHipster will add changesets here, do not remove--> </databaseChangeLog> 

added_entity_constraints_UserExtra:

 <?xml version="1.0" encoding="utf-8"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"> <!-- Added the constraints for entity UserExtra. --> <changeSet id="20180317190851-2" author="jhipster"> <addForeignKeyConstraint baseColumnNames="user_id" baseTableName="user_extra" constraintName="fk_user_extra_user_id" referencedColumnNames="id" referencedTableName="jhi_user"/> </changeSet> </databaseChangeLog> 

Just remember that JHipster uses a table named "JHI_USER" for the "User" object and created a table called "USER_EXTRA" for the new object. We are going to name the primary key / identifier field of the new object "USER_ID":

enter image description here

Step 4: Modify ManagedUserVM.java

The ManagedUserVM class is a kind of DTO that extends the UserDTO that is used in the REST controller. enter image description here

The purpose of this modification is to add new fields that we are going to associate with the User as additional information. Here is a sample code for this class. The phone attribute has been added to the modified class:

 package org.jhipster.web.rest.vm; import org.jhipster.service.dto.UserDTO; import javax.validation.constraints.Size; /** * View Model extending the UserDTO, which is meant to be used in the user management UI. */ public class ManagedUserVM extends UserDTO { public static final int PASSWORD_MIN_LENGTH = 4; public static final int PASSWORD_MAX_LENGTH = 100; @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH) private String password; private String phone; public ManagedUserVM() { // Empty constructor needed for Jackson. } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } @Override public String toString() { return "ManagedUserVM{" + "} " + super.toString(); } } 

Step 5: Modify UserService.java

There is a method in this call called "registerUser" that is responsible for registering a new user:

enter image description here

The purpose of changing this class of service is to make it also add a UserExtra object when a user is added. Here is an example of a modified registeruser method. You can find the added code with the inscription "Create and save UserExtra entity" at the top of the comment:

 public User registerUser(UserDTO userDTO, String password, String phone) { User newUser = new User(); Authority authority = authorityRepository.findOne(AuthoritiesConstants.USER); Set<Authority> authorities = new HashSet<>(); String encryptedPassword = passwordEncoder.encode(password); newUser.setLogin(userDTO.getLogin()); // new user gets initially a generated password newUser.setPassword(encryptedPassword); newUser.setFirstName(userDTO.getFirstName()); newUser.setLastName(userDTO.getLastName()); newUser.setEmail(userDTO.getEmail()); newUser.setImageUrl(userDTO.getImageUrl()); newUser.setLangKey(userDTO.getLangKey()); // 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); cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).evict(newUser.getLogin()); cacheManager.getCache(UserRepository.USERS_BY_EMAIL_CACHE).evict(newUser.getEmail()); 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); log.debug("Created Information for UserExtra: {}", newUserExtra); return newUser; } 

Step 6: Modify AccountResource.java

This class is the REST controller responsible for the actions associated with the Account: enter image description here

This controller has a method called "registerAccount" that calls the "registerUser" method of the UserService class:

 User user = userService.registerUser(managedUserVM, managedUserVM.getPassword()); 

We need to change this line so that we can pass the new fields to the method:

  @PostMapping("/register") @Timed @ResponseStatus(HttpStatus.CREATED) public void registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) { if (!checkPasswordLength(managedUserVM.getPassword())) { throw new InvalidPasswordException(); } userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase()).ifPresent(u -> {throw new LoginAlreadyUsedException();}); userRepository.findOneByEmailIgnoreCase(managedUserVM.getEmail()).ifPresent(u -> {throw new EmailAlreadyUsedException();}); User user = userService.registerUser(managedUserVM, managedUserVM.getPassword(), managedUserVM.getPhone()); mailService.sendActivationEmail(user); } 

Step 7. Change the user interface.

Finally, you need to add the input element to the HTML file:

enter image description here

 <div class="form-group"> <label class="form-control-label" for="phone" data-translate="global.form.phone">Phone number</label> <input type="tel" class="form-control" id="phone" name="phone" #phone="ngModel" placeholder="{{'global.form.phone.placeholder' | translate}}" [(ngModel)]="registerAccount.phone"> </div> 

Then here is what you will have on the registration page:

enter image description here

And here is the data layer:

JHI_USER

enter image description here

USER_EXTRA

enter image description here

PS

The easiest way to do this is to simply add a UserExtra object with a one-to-one relationship to the user via JDL and add "userExtra" when creating a new user.

+6
source

Source: https://habr.com/ru/post/1014632/


All Articles