#RequestParam with any value - java

I have the following metod in my #Restcontroller:
#GetMapping
public List<User> getByParameterOrAll(
#RequestParam(value = "email", required = false) String email,
#RequestParam(value = "phone", required = false) String phone) {
List<User> userList;
if ((email != null && !email.isEmpty()) && (phone == null || phone.isEmpty())) {
userList = super.getByEmail(email);
} else if ((email == null || email.isEmpty()) && (phone != null)) {
userList = super.getByPhone(phone);
} else {
userList = super.getAll();
}
return userList;
}
This method allows to handle following GET-requests:
GET: /customers/
GET: /customers?email=emai#email.com
GET: /customers?phone=8-812-872-23-34
But if necessary to add some more parameters for request. If it will be 10 or... 20 params,body of above method arrise outrageously!
If there any way to pass value of #RequestParam to the method-body, I could realize, for example:
#GetMapping
public List<User> getByParameterOrAll(
#RequestParam(value = "any", required = false) String any) {
if (value=="email") {
userList = super.getByEmail(email);
} else if (value=="email") {
userList = super.getByPhone(email);
} else if .....
}
Is there any way to use #RequestParam-value in method-body?

#RequestParam
When an #RequestParam annotation is declared as a Map
or MultiValueMap, without a parameter name specified
in the annotation, then the map is populated with the request
parameter values for each given parameter name.
#GetMapping
public List<User> getByParameterOrAll(#RequestParam Map<String, String> parameters){
....
}
will get you all the parameters and values as a map.

You can't use single #RequestParam for different name-value on the request. Another way for you can be retrieve all #RequestParam of the request like this aswer

You can just add HttpServletRequest as a method parameter and Spring will give it to you:
#GetMapping
public List<User> getByParameterOrAll(#RequestParam(value = "email", required = false)
String email,
#RequestParam(value = "phone", required = false)
String phone, HttpServletRequest request)
Then, you can use the HttpServletRequest API to get the list of parameters passed:
request.getParameterNames() or request.getParameterMap()
See the docs here:
https://docs.oracle.com/javaee/6/api/javax/servlet/ServletRequest.html#getParameterMap()

Related

Spring Boot Rest Web Service fetching multiple parameters in Get Request

I am creating Spring Boot Web service and I have a Model Employee
public class Employee {
private String id;
private String name;
private String designation;
private int salary;
//Has Getters and Setters
}
I want to create a Get request which will fetching and filter the List of Employees based on the parameters given by user.
For example, if the user gives name of an employee and designation of employee, the get method should filter those result. For various combination of parameters it should work.
#Override
public List<Employee> getEmployees(Map<String, Object> parameters) {
if (parameters.size() == 0)
// code to return all employees;
List<Employee> selectedEmployees = new ArrayList<Employee>();
for(Employee currentEmployee: new ArrayList<Employee>(employee.values())) {
for(Map.Entry<String, Object> check: parameters.entrySet()) {
try {
if(check.getValue() instanceof Integer) {
int condition = (int) Employee.class.getMethod("get" + check.getKey()).invoke(currentEmployee);
if((int) check.getValue() == condition)
selectedEmployees.add(currentEmployee);
} else if (check.getValue() instanceof String) {
String condition = (String) Employee.class.getMethod("get" + check.getKey()).invoke(currentEmployee);
if (((String) check.getValue()).equals(condition))
selectedEmployees.add(currentEmployee);
}
} catch(Exception e){
e.printStackTrace();
}
}
}
return selectedEmployees;
}
In order to avoid multiple if else cases I am filtering list based on String and Integer above.
I think I am making an error in the below code which sending request in Controller.
#RequestMapping(value={"/employees","/{id}/{name}/{designation}/{salary}"})
public List<Employee> getEmployeeByProperty(EmployeeRequestParameters requestParams){
//Map for storing parameters to filter the List
Map<String, Object> filterParams = new HashMap<>();
if(requestParams.getIdParam().isEmpty()) {
filterParams.put("id", Integer.parseInt(requestParams.getIdParam()));
}
if(!requestParams.getNameParam().isEmpty()) {
filterParams.put("name", requestParams.getNameParam());
}
if(!requestParams.getDesignationParam().isEmpty()) {
filterParams.put("designation", requestParams.getDesignationParam());
}
if(requestParams.getSalaryParam().isEmpty()) {
filterParams.put("salary", Integer.parseInt(requestParams.getSalaryParam()));
}
return EmployeeService.getEmployeesByProperty(filterParams);
}
If {id} field is not full, {name} or {designation} or {salary} to be null.For {name} or {designation} or {salary} to be full Because should be {id} full.
#GetMapping("/employees")
public List<Employee> getEmployeeByProperty(#RequestParam(value = "id", required=false) String id,
#RequestParam(value = "name", required=false) String name,
#RequestParam(value = "designation", required=false) String designation,
#RequestParam(value = "salary", required=false) int salary) {
//Your codes
}
Even if {id} is empty, you can use others.

spring boot find by field search specification

My problem is I can search from database. But I did searching by using findAll of JpaSpecificationExecutor. But, I want to do searching by using findById and pass my specification, pageable and id to it return page. But it is not working.
Here is my controller:
#GetMapping(value = "/search")
public ResponseEntity<ResponseDTO> allAccountRightService(
#RequestParam(value = "search", required = false) String search,
#RequestParam(value = "page", required = false) Integer page,
#RequestParam(value = "size", required = false) Integer size,
#RequestParam(value = "order", required = false) String order,
#RequestParam(value = "orderBy", required = false) String orderBy) {
ResponseDTO responseDTO = new ResponseDTO("accountRightService List", accountRightService.search(search, page, size, order, orderBy));
return new ResponseEntity<>(responseDTO, HttpStatus.OK);
}
and here is my `service impl` method:
public Map<PageInformation, List<AccountRightDTO>> search(String search, Integer page, Integer size, String order,
String orderBy) {
Map<PageInformation, List<AccountRightDTO>> accountRightList = new HashMap<>();
PageInformation pageInfo = new PageInformation();
if (order == null || order.isEmpty())
order = "DESC";
if (orderBy == null || orderBy.isEmpty())
orderBy = "createdAt";
Pageable pageable = CommonUtil.createPageRequest(page, size, order, orderBy);
Specification<AccountRight> spec = CommonUtil.buildSearchSpecification(search);
//Page<AccountRight> accountRightPage = accountRightRepository.findAllByRightByAppointment(CommonUtil.getAppointment().getAppointmentID(), spec, pageable);
Page<AccountRight> accountRightPage = accountRightRepository.findAll(spec, pageable);
List<AccountRight> accountRights = accountRightPage.getContent();
List<AccountRightDTO> accountRightDTOs = new ArrayList<>();
accountRightDTOs = accountRights.stream().map(accountRight -> {
AccountRightDTO accountRightDTO = new AccountRightDTO();
AppointmentDTO rightToAppointmentDTO = new AppointmentDTO();
AppointmentDTO rightByAppointmentDTO = new AppointmentDTO();
BeanUtils.copyProperties(accountRight, accountRightDTO, "accountRightID");
accountRightDTO.setAccountRightID(Long.toString(accountRight.getAccountRightID()));
BeanUtils.copyProperties(accountRight.getRightToAppointment(), rightToAppointmentDTO, "appointmentID");
rightToAppointmentDTO.setAppointmentID(Long.toString(accountRight.getRightToAppointment().getAppointmentID()));
BeanUtils.copyProperties(accountRight.getRightByAppointment(), rightByAppointmentDTO, "appointmentID");
rightByAppointmentDTO.setAppointmentID(Long.toString(accountRight.getRightToAppointment().getAppointmentID()));
accountRightDTO.setRightByAppointment(rightByAppointmentDTO);
accountRightDTO.setRightToAppointment(rightToAppointmentDTO);
return accountRightDTO;
}).collect(Collectors.toList());
pageInfo.setSize(accountRightPage.getSize());
pageInfo.setTotalElements(accountRightPage.getTotalElements());
pageInfo.setTotalPages(accountRightPage.getTotalPages());
accountRightList.put(pageInfo, accountRightDTOs);
return accountRightList;
}
and this is my buildsearchspecification method
public static <T> Specification<T> buildSearchSpecification(String search) {
SearchSpecificationsBuilder<T> builder = new SearchSpecificationsBuilder<T>();
if (search != null && !search.isEmpty()) {
String[] str = search.split(",");
if (str != null) {
for (String strTemp : str) {
Pattern pattern = Pattern.compile("(\\p{Punct}?)(.*)(:|!|<|>|~)(.*)(\\p{Punct}?),");
Matcher matcher = pattern.matcher(strTemp + ",");
while (matcher.find()) {
builder.with(matcher.group(1), matcher.group(2),
SearchOperation.getSimpleOperation(matcher.group(3).toCharArray()[0]),
matcher.group(4));
}
}
}
}
Specification<T> spec = builder.build();
return spec;
}
and here is my findAllByRightByAppointment repository method
#Query("select account from AccountRight account where account.rightByAppointment.appointmentID=?1")
Page<AccountRight> findAllByRightByAppointment(Long appointmentID, #Nullable Specification<AccountRight> spec, Pageable pageable);
If I use findAll method than searching will work otherwise by using my custom method pagination works without searching
I found an answer by using Specification.Where(your_specification).and(your_search_specification).
here is my updated code now:
Specification<AccountRight> searchSpec = CommonUtil.buildSearchSpecification(search); //this specification needs my search string.
SearchSpecification<AccountRight> rightByAppointmentID =
new SearchSpecification<AccountRight>(new SearchCriteria("rightByAppointment.appointmentID", SearchOperation.EQUALITY, CommonUtil.getAppointment().getAppointmentID())); //this specification accepts search criteria with key, operation and value.
Page<AccountRight> accountRightPage = accountRightRepository.findAll(Specification.where(rightByAppointmentID).and(searchSpec), pageable);
//here you will just tell findAll method to findAll entities where rightByAppointmentID is equal to
//CommonUtil.getAppointment().getAppointmentID() and search query is searchSpec

How to get param in url like /api/groups?sdk&type=1 with java?

For example, URL can be:
/api/groups?sdk&type=1
or
/api/groups?app&type=1
In java, I want to know the param in the url is sdk or app.
I have tried something like:
#RequestMapping(method = RequestMethod.GET)
public ResponseResult testGet(HttpServletRequest request, #RequestParam String sdk, #RequestParam int type) {
...
}
Basically you can have 2 methods and use the params variable in the #RequestMapping anotation to discriminate between the methods.
#RequestMapping(method = RequestMethod.GET, params="sdk")
public ResponseResult getSdk(HttpServletRequest request, #RequestParam int type) {
...
}
#RequestMapping(method = RequestMethod.GET, params="app")
public ResponseResult getApp(HttpServletRequest request, #RequestParam int type) {
...
}
You may or may not need to add the value = "/groups" to your request mapping, depending on how you have configured your class/app.
you can use a parameter for app and sdk so your url will be /api/groups?param=sdk&type=1 or /api/groups?param=app&type=1. you can find sample code below:
#RequestMapping(value = "/groups", method = RequestMethod.GET)
public RestResponse testGet(#RequestParam(value = "param", required = false) String param, #RequestParam(value = "type", required = false) String type) {
}

How to access data from RestTemplate as List

I want to access data from a spring boot service. The return type of the data is a List, but every time I access it, the list is empty.
This is my code:
Map<String, String> params = new HashMap<String, String>();
params.put("firstName", "test" );
params.put("lastName", "test1");
ResponseEntity<Person[]> response = restTemplate.getForEntity(url, Person[].class, params);
In this case, response.getBody() is an empty [].
#RequestMapping(value = "/search", method = RequestMethod.GET)
public List<Person> searchUsers(
#RequestParam(value = "firstName", required = false) String firstName,
#RequestParam(value = "lastName", required = false) String lastName,
#RequestParam(value = "email", required = false) String email {
return personService.search(firstName, lastName, email, company);
}
I also tried with String, and Person[], but nothing worked.
Thanks in advance!
#GET
#Path("statement")
#Produces({MediaType.APPLICATION_XML})
public Response statement(#QueryParam("from") String from, #QueryParam("to") String to) {
DB idb = new DB();
List<Transaction> transactions = idb.getTransactionsByDate(from, to);
final GenericEntity<List<Transaction>> entity = new GenericEntity<List<Transaction>>(transactions) {
};
return Response.status(Response.Status.OK).entity(entity).build();
}

spring-data-mongodb optional query parameter

I am using spring-data-mongodb.
I want to query database by passing some optional parameter in my query.
I have a domain class.
public class Doc {
#Id
private String id;
private String type;
private String name;
private int index;
private String data;
private String description;
private String key;
private String username;
// getter & setter
}
My controller:
#RequestMapping(value = "/getByCategory", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
public Iterable<Doc> getByCategory(
#RequestParam(value = "key", required = false) String key,
#RequestParam(value = "username", required = false) String username,
#RequestParam(value = "page", required = false, defaultValue = "0") int page,
#RequestParam(value = "size", required = false, defaultValue = "0") int size,
#RequestParam(value = "categories") List<String> categories)
throws EntityNotFoundException {
Iterable<Doc> nodes = docService.getByCategory(key, username , categories, page, size);
return nodes;
}
Here Key and username are optional query parameters.
If I pass any one of them it should return the matching document with given key or username.
My service method is:
public Iterable<Doc> getByCategory(String key, String username, List<String> categories, int page, int size) {
return repository.findByCategories(key, username, categories, new PageRequest(page, size));
}
Repository:
#Query("{ $or : [ {'key':?0},{'username':?1},{categories:{$in: ?2}}] }")
List<Doc> findByCategories(String key, String username,List<String> categories, Pageable pageable);
But by using above query it does not returns a document with either given key or username.
What is wrong in my query?
This is how I am making request
http://localhost:8080/document/getByCategory?key=key_one&username=ppotdar&categories=category1&categories=category2
Personally, I'd ditch the interface-driven repository pattern at that point, create a DAO that #Autowires a MongoTemplate object, and then query the DB using a Criteria instead. that way, you have clear code that isn't stretching the capabilities of the #Query annotation.
So, something like this (untested, pseudo-code):
#Repository
public class DocDAOImpl implements DocDAO {
#Autowired private MongoTemplate mongoTemplate;
public Page<Doc> findByCategories(UserRequest request, Pageable pageable){
//Go through user request and make a criteria here
Criteria c = Criteria.where("foo").is(bar).and("x").is(y);
Query q = new Query(c);
Long count = mongoTemplate.count(q);
// Following can be refactored into another method, given the Query and the Pageable.
q.with(sort); //Build the sort from the pageable.
q.limit(limit); //Build this from the pageable too
List<Doc> results = mongoTemplate.find(q, Doc.class);
return makePage(results, pageable, count);
}
...
}
I know this flies in the face of the trend towards runtime generation of DB code, but to my mind, it's still the best approach for more challenging DB operations, because it's loads easier to see what's actually going on.
Filtering out parts of the query depending on the input value is not directly supported. Nevertheless it can be done using #Query the $and operator and a bit of SpEL.
interface Repo extends CrudRepository<Doc,...> {
#Query("""
{ $and : [
?#{T(com.example.Repo.QueryUtil).ifPresent([0], 'key')},
?#{T(com.example.Repo.QueryUtil).ifPresent([1], 'username')},
...
]}
""")
List<Doc> findByKeyAndUsername(#Nullable String key, #Nullable String username, ...)
class QueryUtil {
public static Document ifPresent(Object value, String property) {
if(value == null) {
return new Document("$expr", true); // always true
}
return new Document(property, value); // eq match
}
}
// ...
}
Instead of addressing the target function via the T(...) Type expression writing an EvaluationContextExtension (see: json spel for details) allows to get rid of repeating the type name over and over again.

Categories