0

How can I develop a method generic to retrieve data by attribute. Let's say we have a User Class

public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
private String password;
private String firstName;
private String lastName;

}

UserRepository

public interface  UserRepository  extends CrudRepository<User, Long> {
    
    Optional<User> findOneByUsername(String username);
    Optional<User> findUsersByAttributes(String attribute);
    
}

I want to develop a method to retrieve data by attribute :

findUsersByAttributes(String attribute){

}
Pooja S
  • 550
  • 2
  • 9
user4343
  • 27
  • 7
  • 2
    Try QueryDsl or Specification class – pvpkiran Jun 11 '18 at 12:40
  • This should not be possible, but if you have few attributes you can write a method for each of them. If you need to combine multiple attributes like `findAllByFirstNameAndLastnameAndMoreAttributes` then above comment is a better solution, as the amount of options would grow too fast. – Glains Jun 11 '18 at 12:44
  • @Glains @pvpkiran can explain more or example : what i expected it's when user send like : `*/user?lastname=Johon // retrive data for Johon` `*/user?userName=Red // retrive data for Red` So the filter based parameter – user4343 Jun 13 '18 at 11:17
  • @user4343 See my anser below. I hope that it helps. – Glains Jun 13 '18 at 14:18

1 Answers1

0

Entity

You already provided your entity, but i added the missing annotations so it can be picked up by any jpa implementation. Just a quick reminder here, whenever you store a password you should consider hashing passwords and not store them as plaintext in your database. You can find more information about this here.

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

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

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

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

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

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

    // remainer ommitted for brevity
}    

Repository

The most simple option is to create methods using Spring Data JPA.

@Repository
public interface UserRepository extends CrudRepository<User, Long> {

    Optional<User> findOneByUsername(String username);
    List<User> findAllByFirstName(String firstName);
    List<User> findAllByLastName(String lastName);
}

However, consider the case where you might want to query users for more attributes at the same time. For example, if you want to find a user by firstName, lastName, gender, phoneNumber, ... it would be impossible to write methods for all sorts of combinations.

findAllByFirstNameAndLastNameAndGenderAndPhoneNumber // pretty confusing

If you only need a few properties, you can use CrudRepository as stated above, if you need more properties you might want to have a look at QueryDSL or Specifications, which deal exactly with that problem. More information about this here.

Service

Next up, you should create a service to decouple your data layer.

@Service
public class UserService {

    private UserRepository repository;

    @Autowired
    public UserService(UserRepository repository) {
        this.repository = repository;
    }

    Optional<User> findOneByUsername(String username) {
        return repository.findOneByUsername(username);
    }

    List<User> findAllByFirstName(String firstName) {
        return repository.findAllByFirstName(firstName);
    }

    List<User> findAllByLastName(String lastName) {
       return repository.findAllByLastName(lastName);
    }
}

Controller

Finally, create a controller to access you service layer.

@RestController
@RequestMapping("/users")
public UserController {

    private UserService service;

    @Autowired
    public UserController(UserService service) {
        this.service = service;
    }

    @GetMapping()
    @ResponseBody
    public List<User> findAll(@RequestParam(value = "username", required = false) String username, 
          @RequestParam(value = "firstName", required = false) String firstName, 
          @RequestParam(value = "lastName", required = false) String lastName) {
        if (username != null) {
            return List.of(service.findOneByUsername(username));
        }
        if (firstName != null) {
            return service.findAllByFirstName(username);
        }
        if (lastName!= null) {
            return service.findAllByLastName(username);
        }
        return service.findAll();
    }
}

One last note here, think about whether you want to make you password field also available in requests, if not i would recommend using a UserDTO and ModelMapper.

Glains
  • 2,773
  • 3
  • 16
  • 30