Spring MVC custom class name parameter binding

As all know, spring mvc during the time parameter binding. Class name parameter names defined by the rear end of the front end of the request is one to one. For example: a name request parameter value has reached the rear end. Backend only need to define a class, then the class which declares a name attribute. When the transmission request of the spring mvc value automatically filled into the class name of this definition. When you encounter such a problem is to define a front-end goods_name (trade name), if the backend of course, also declared a goods_name such properties can be added to it. However, this operation is not enough elegance.

I encountered this problem is through the beginning of the idea of ​​automatic conversion spring to do. But each automatic type conversions are trying to find it will not work. Finally, using spring mvc request parameter binding (HandlerMethodArgumentResolver) to do such things.

Ideas are as follows:

When making the request parameter bindings it creates an object from the request parameter request method inside, and then injecting through the injection dependency spring inside the request object data to the object created.

My idea is custom parameter parser bind parameters into between two steps above through. My first request a custom parameter binding parser, and then declare a note in which class, name the attribute name with the corresponding class attribute of the request object inside the association. After being created, the value of the corresponding class attributes come from the request object is then reflected by the value setter into.

Specific code as follows:

1, Key.java

Custom annotation class, association request request object class attributes and attribute names

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Key {

    String value() default "";

}

2、EnableKey

Annotation custom class for label declaration parser to parse request parameter binding parameters corresponding to the resolution request url requests.

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableKey {

}

3、CustomModelAttributeMethodProcessor.java

Custom parameter parsing class, the class name for the custom parameter binding.

public class CustomModelAttributeMethodProcessor extends ModelAttributeMethodProcessor {

    public CustomModelAttributeMethodProcessor(boolean annotationNotRequired) {
        super(annotationNotRequired);
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(EnableKey.class);
    }

    @Override
    protected Object createAttribute(String attributeName, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception {
        Object result = super.createAttribute(attributeName, parameter, binderFactory, request);
        Class<?> targetClazz = result.getClass();
        for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(targetClazz)) {
            //skip class
            if (pd.getName().equals("class")){
                continue;
            }
            TypeDescriptor td = build(targetClazz, pd);
            Key key = td.getAnnotation(Key.class);
            if(key != null && StringUtils.isNotBlank(key.value())){
                ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
                MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(servletRequest);
                addBindValues(mpvs, servletRequest);
                PropertyValue propertyValue = mpvs.getPropertyValue(key.value());
                if(propertyValue != null){
                    String value = (String) propertyValue.getValue();
                    pd.getWriteMethod().invoke(result, value);
                }
            }

        }
        return result;
    }

    private TypeDescriptor build(Class<?> beanClz, PropertyDescriptor pd) {
        Property p = new Property(beanClz, pd.getReadMethod(), pd.getWriteMethod(), pd.getName());
        return new TypeDescriptor(p);
    }

    protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) {
        String attr = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE;
        Map<String, String> uriVars = (Map<String, String>) request.getAttribute(attr);
        if (uriVars != null) {
            uriVars.forEach((name, value) -> {
                if (mpvs.contains(name)) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Skipping URI variable '" + name +
                                "' because request contains bind value with same name.");
                    }
                }
                else {
                    mpvs.addPropertyValue(name, value);
                }
            });
        }
    }

    @Override
    protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
        ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
        Assert.state(servletRequest != null, "No ServletRequest");
        ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
        servletBinder.bind(servletRequest);
    }

}

4、WebMvcConfig.java

spring mvc configuration class, the parser is added to the custom parameter resolver spring mvc among the list of parameters.

@EnableWebMvc
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new CustomModelAttributeMethodProcessor(true));
    }

}

5、User.java

POJO class is defined for receiving a request parameter.

@Data
public class User {

    private String id;
    private String name;
    private boolean flag;
    @Key("bank_type")
    private String bankType;

}

6、UserController.java

controller test class.

@RestController
@RequestMapping(value = "test")
public class UserController {

    @RequestMapping(value = "/user/add")
    public void add(@EnableKey User user){
        System.out.println(user);
    }

}

Sending a request using the postman:

Here Insert Picture Description
Console requires the User object:

Here Insert Picture Description
Such is the request object can be bound to the background bank_type bankType the above property.

Published 173 original articles · won praise 221 · views 700 000 +

Guess you like

Origin blog.csdn.net/u012410733/article/details/100732730