Spring MVC中@RequestParam的自定义转换器

tvmytwxo  于 2023-08-06  发布在  Spring
关注(0)|答案(4)|浏览(167)

我正在将加密的String作为Query参数获取到Spring rest控制器方法。
我想在字符串到达基于一些注解(比如@Decrypt)的方法之前对其进行解密,如下所示

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

字符串
在这个用例中,定制的Formatter是正确的方法吗?
或者我应该使用自定义HandlerMethodArgumentResolver

carvr3hs

carvr3hs1#

org.springframework.format.Formatter的自定义实现是此用例的有效方法。这就是Spring本身如何实现日期,货币,数字样式等的格式化程序。
步骤:
1.声明注解:Decrypt

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
public @interface Decrypt {

}

字符串
1.声明一个使用新注解的AnnotationFormatterFactory

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 e.g. 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();
            }
        };
    }
}


1.将此格式化程序工厂注册到您的Web上下文:

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());
    }
}


1.就这样了
有了上面的内容,所有使用@Decrypt限定的@RequestParam都将通过DecryptAnnotationFormatterFactory中声明的parse()方法传递,因此您可以在那里实现解密调用。
为了证明这一点,以下测试通过:

@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"));
    }
}

9udxz4iz

9udxz4iz2#

HandlerMethodArgumentResolver在这方面是最好的。
1.创建注解:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Decrypt {
    String value();
}

字符串
1.创建自定义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.注册冲突解决程序:

@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.瞧,你有你的解密参数。请注意,您不再需要使用@RequestParam。

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

qjp7pelc

qjp7pelc3#

您可以尝试在web.xml文件中添加CharacterEncodingFilterinit-paramencodingUTF-8。查看this example
但是如果仍然不起作用,您可以通过添加下面的参数沿着上面的init-param来强制编码。

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

字符串
让我知道如果它为你工作。

gijlo24d

gijlo24d4#

如果您将解密的数据 Package 在数据传输对象中,则可以使用Spring的Converter框架。

public class Decrypted { // data transfer object

    private final String value;

    public Decrypted(String value){
        this.value = value;
    }

    public String get(){
        return value;
    }
}

字符串
实现接口org.springframework.core.convert.converter.Converter,并添加@Component注解。

@Component
public class DecryptConverter implements Converter<String, Decrypted> {
    @Override
    public Decrypted convert(String value) {
        return new Decrypted(decrypt(value)); // you implement "decrypt"
    }
}


然后注册

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new DecryptConverter());
    }
}


然后为参数使用 Package 器类型(Decrypted):

@RequestMapping(value = "/customer", method = RequestMethod.GET)
public String getAppointmentsForDay(@RequestParam("secret") Decrypted customerSecret) {
    System.out.println(customerSecret.get());  // decrypted value
}


参见https://www.baeldung.com/spring-enum-request-param

相关问题