Spring Web MVC - Validate Individual Request Params

Spring Web MVC - validate individual request params

There's nothing built in to do that, not yet anyway. With the current release versions you will still need to use the WebDataBinder to bind your parameters onto an object if you want automagic validation. It's worth learning to do if you're using SpringMVC, even if it's not your first choice for this task.

It looks something like this:

public ModelAndView createFoo(@PathVariable long level1,
@PathVariable long level2,
@Valid @ModelAttribute() FooWrapper fooWrapper,
BindingResult errors) {
if (errors.hasErrors() {
//handle errors, can just return if using Spring form:error tags.
}
}

public static class FooWrapper {
@NotNull
@Size(max=32)
private String fooName;
private String description;
//getset
}

If you have Hibernate Validator 4 or later on your classpath and use the default dispatcher setup it should "Just work."

Editing since the comments were getting kind of large:

Any Object that's in your method signature that's not one of the 'expected' ones Spring knows how to inject, such as HttpRequest, ModelMap, etc, will get data bound. This is accomplished for simple cases just by matching the request param names against bean property names and calling setters. The @ModelAttribute there is just a personal style thing, in this case it isn't doing anything. The JSR-303 integration with the @Valid on a method parameter wires in through the WebDataBinder. If you use @RequestBody, you're using an object marshaller based on the content type spring determines for the request body (usually just from the http header.) The dispatcher servlet (AnnotationMethodHandlerAdapter really) doesn't have a way to 'flip the validation switch' for any arbitrary marshaller. It just passes the web request content along to the message converter and gets back a Object. No BindingResult object is generated, so there's nowhere to set the Errors anyway.

You can still just inject your validator into the controller and run it on the object you get, it just doesn't have the magic integration with the @Valid on the request parameter populating the BindingResult for you.

Spring Boot : Custom Validation in Request Params

Case 1: If the annotation ValuesAllowed is not triggered at all, it could be because of not annotating the controller with @Validated.

@Validated
@ValuesAllowed(propName = "orderBy", values = { "OpportunityCount", "OpportunityPublishedCount", "ApplicationCount", "ApplicationsApprovedCount" })
public class OpportunityController {
@GetMapping("/vendors/list")
public String getVendorpage(@RequestParam(required = false) String term,..{
}

Case 2: If it is triggered and throwing an error, it could be because of the BeanUtils.getProperty not resolving the properties and throwing exceptions.

If the above solutions do not work, you can try moving the annotation to the method level and update the Validator to use the list of valid values for the OrderBy parameter. This worked for me. Below is the sample code.

@RestController
@RequestMapping("/api/opportunity")
@Validated
public class OpportunityController {
@GetMapping("/vendors/list")
public String getVendorpage(@RequestParam(required = false) String term,
@RequestParam(required = false) Integer page, @RequestParam(required = false) Integer size,
@ValuesAllowed(propName = "orderBy", values = { "OpportunityCount", "OpportunityPublishedCount", "ApplicationCount",
"ApplicationsApprovedCount" }) @RequestParam(required = false) String orderBy, @RequestParam(required = false) String sortDir) {
return "success";
}
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { ValuesAllowed.Validator.class })
public @interface ValuesAllowed {

String message() default "Field value should be from list of ";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

String propName();

String[] values();

class Validator implements ConstraintValidator<ValuesAllowed, String> {
private String propName;
private String message;
private List<String> allowable;

@Override
public void initialize(ValuesAllowed requiredIfChecked) {
this.propName = requiredIfChecked.propName();
this.message = requiredIfChecked.message();
this.allowable = Arrays.asList(requiredIfChecked.values());
}

public boolean isValid(String value, ConstraintValidatorContext context) {
Boolean valid = value == null || this.allowable.contains(value);

if (!valid) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message.concat(this.allowable.toString()))
.addPropertyNode(this.propName).addConstraintViolation();
}
return valid;
}
}
}

spring validation for requestparam not working

You have done the following 2 steps correctly:

  1. Included the hibernate validator to the pom.xml
  2. Added @Validated annotation to the controller

Two more steps are required. Can you do these two in addition to above:


  1. Add one more entry to the pom.xml (not sure about why the javax.el is needed)

     

    <dependency>
    <groupId>org.glassfish </groupId>
    <artifactId>javax.el </artifactId>
    <version>3.0.1-b11 </version>
    </dependency>

  2. Add the following to your Java Configuration class

     

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
    return new MethodValidationPostProcessor();
    }

(refer - https://www.baeldung.com/spring-validate-requestparam-pathvariable)

How to make validations work with @RequestParam

I generated a Spring project from https://start.spring.io/ as shown below:

Sample Image

I then added the controller code in your question, and an integration test as below:

class DemoApplicationTests {
@Autowired
private MockMvc mockMvc;

@Test
void testGoodInput() throws Exception {
mockMvc
.perform(MockMvcRequestBuilders.get("/test?val=10"))
.andExpect(MockMvcResultMatchers.status().isOk());
}

@Test
void testBadInput() {
Throwable ex = catchThrowable(() -> mockMvc
.perform(MockMvcRequestBuilders.get("/test?val=0"))
.andReturn());
var cause = getViolationExceptionFromCause(ex);
assertThat(cause)
.isInstanceOf(ConstraintViolationException.class);
}

private ConstraintViolationException getViolationExceptionFromCause(Throwable ex) {
if (ex == null || ex instanceof ConstraintViolationException) {
return (ConstraintViolationException) ex;
}
return getViolationExceptionFromCause(ex.getCause());
}
}

This works as expected, val=0 throws a ConstraintViolationException. It's your turn to prove otherwise.

How to validate request parameter key in springs

You can declare your request param as optional. Then you can check it manually whether it exists or not. Depending on it you can show custom error message. For example -

@Scope("request")
@RestController
public class GetOperatorSeries{
@RequestMapping(value = "test", method = RequestMethod.GET)
public String getOperatorSeries(HttpServletResponse response, @RequestParam(value = "mobno") long mobno,
@RequestParam(value = "sourceType", required=false) String sourceType,
@RequestParam(value = "responseType") String responseType, Model model)
{

if (sourceType == null) {
model.addAttribute("errorMessage", "Source Type is missing");
return "viewName"; // Now show the error message in view. You can also add this error as flash attribute. You can also show a new error page.

}

}

Spring MVC - How to check that no unexpected query string parameters has been passed?

You could implement your own HandlerInterceptor. In preHandle method you can obtain all HandlerMethod's parameters annotated with @RequestParameter. These will be all allowed parameters in request.



Related Topics



Leave a reply



Submit