Custom Converter for @RequestParam to Spring MVC

I get the encrypted String as Query parameter to the Spring break controller method.

I wanted to decrypt the string before it reaches a method based on some annotation (say @Decrypt ), as shown below

 @RequestMapping(value = "/customer", method = RequestMethod.GET) public String getAppointmentsForDay(@RequestParam("secret") @Decrypt String customerSecret) { System.out.println(customerSecret); // Needs to be a decrypted value. ... } 

Is the usual Formatter right approach in this case?

Or should I use a custom HandlerMethodArgumentResolver ?

+5
source share
3 answers

A custom implementation of org.springframework.format.Formatter is a valid approach for this use case. Thus, Spring itself implements formatting for dates, currencies, number styles, etc.

Steps:

  • Announcement Announcement: Decrypt :

     import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE}) public @interface Decrypt { } 
  • Declare AnnotationFormatterFactory , which uses the new annotation:

     import org.springframework.context.support.EmbeddedValueResolutionSupport; import org.springframework.format.AnnotationFormatterFactory; import org.springframework.format.Formatter; import org.springframework.format.Parser; import org.springframework.format.Printer; import java.text.ParseException; import java.util.Collections; import java.util.HashSet; import java.util.Locale; import java.util.Set; public class DecryptAnnotationFormatterFactory extends EmbeddedValueResolutionSupport implements AnnotationFormatterFactory<Decrypt> { @Override public Set<Class<?>> getFieldTypes() { Set<Class<?>> fieldTypes = new HashSet<>(); fieldTypes.add(String.class); return Collections.unmodifiableSet(fieldTypes); } @Override public Printer<String> getPrinter(Decrypt annotation, Class<?> fieldType) { return configureFormatterFrom(annotation); } @Override public Parser<String> getParser(Decrypt annotation, Class<?> fieldType) { return configureFormatterFrom(annotation); } private Formatter<String> configureFormatterFrom(Decrypt annotation) { // you could model something on the Decrypt annotation for use in the decryption call // in this example the 'decryption' call is stubbed, it just reverses the given String // presumaby you implementaion of this Formatter will be different eg it will invoke your encryption routine return new Formatter<String>() { @Override public String print(String object, Locale locale) { return object; } @Override public String parse(String text, Locale locale) throws ParseException { return new StringBuilder(text).reverse().toString(); } }; } } 
  • Register this factory formatter with your web context:

     import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration public class WebConfigurer extends WebMvcConfigurerAdapter { @Override public void addFormatters(FormatterRegistry registry) { super.addFormatters(registry); registry.addFormatterForFieldAnnotation(new DecryptAnnotationFormatterFactory()); } } 
  • What is it.

Using the above, all uses of @RequestParam that qualify with @Decrypt will be passed through the parse() method declared in DecryptAnnotationFormatterFactory so you can implement your decryption call there.

To prove this, the following tests are performed:

 @RunWith(SpringRunner.class) @WebMvcTest(controllers = YourController.class) public class YourControllerTest { @Autowired private MockMvc mockMvc; @Test public void theSecretRequestParameterWillBeConverted() throws Exception { MvcResult mvcResult = mockMvc.perform(get("/customer?secret=abcdef")).andExpect(status().isOk()).andReturn(); // the current implementation of the 'custom' endpoint returns the value if the secret request parameter and // the current decrypt implementation just reverses the given value ... assertThat(mvcResult.getResponse().getContentAsString(), is("fedcba")); } } 
+4
source

HandlerMethodArgumentResolver will be the best in this regard.

  • Create annotation:

 @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Decrypt { String value(); } 
  1. Create your own HandlerMethodArgumentResolver:
 public class DecryptResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterAnnotation(Decrypt.class) != null; } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Decrypt attr = parameter.getParameterAnnotation(Decrypt.class); String encrypted = webRequest.getParameter(attr.value()); String decrypted = decrypt(encrypted); return decrypted; } private String decrypt(String encryptedString) { // Your decryption logic here return "decrypted - "+encryptedString; } } 
  1. Register Recognizer:
 @Configuration @EnableMvc // If you're not using Spring boot public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new DecryptResolver()); } } 
  1. Will, you have a decrypted parameter. Please note that you will no longer need to use @RequestParam.
 @RequestMapping(value = "/customer", method = RequestMethod.GET) public String getAppointmentsForDay(@Decrypt("secret") String customerSecret) { System.out.println(customerSecret); // Needs to be a decrypted value. ... } 
+2
source

You can try adding CharacterEncodingFilter with init-param encoding UTF-8 to the web.xml file. Check out this example .

However, if it still does not work, you can force it by adding the following parameter along with init-param above.

 <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> 

Let me know if this works for you.

0
source

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


All Articles