码迷,mamicode.com
首页 > 编程语言 > 详细

SpringBoot08 请求方式、参数获取注解、参数验证、前后台属性名不一致问题、自定义参数验证注解、BeanUtils的使用

时间:2018-01-03 22:47:45      阅读:458      评论:0      收藏:0      [点我收藏+]

标签:data   get   chm   hash   initial   ati   amp   apach   prefix   

 

1 请求方式

  在定义一个Rest接口时通常会利用GET、POST、PUT、DELETE来实现数据的增删改查;这几种方式有的需要传递参数,后台开发人员必须对接收到的参数进行参数验证来确保程序的健壮性

  1.1 GET

    一般用于查询数据,采用明文进行传输,一般用来获取一些无关用户信息的数据

  1.2 POST

    一般用于插入数据

  1.3 PUT

    一般用于数据更新

  1.4 DELETE

    一般用于数据删除

    技巧01:一般都是进行逻辑删除(即:仅仅改变记录的状态,而并非真正的删除数据)

2 参数获取注解

  2.1 @PathVariable

    路径参数,形如 url/{param} 时会用到,我们可以通过该注解来获取路径后面的参数来进行GET、DELETE、PUT操作

    技术分享图片

技术分享图片
@GetMapping(value = "/{id}")
    public ResultViewModel findGirlById(
            @PathVariable("id") String id
    ) {
        // 01 参数去空格
        id = StringUtils.trim(id);

        // 02 判断参数是否全为数字
        Integer girlId = 0;
        if (JudgeUtil.allIsNumber(id)) {
            girlId = Integer.parseInt(id);
        } else {
            throw new GirlException(GirlEnum.PARAM_NOT_ALL_NUMBER);
        }

        // 03 调用服务层获取数据
        return ResultViewModelUtil.success(girlService.findGirlById(girlId));
    }
View Code

  2.2 @RequestParam

    用来获取多个参数,常用语POST、PUT操作

  2.3 @RequestBody

    利用一个对象去获取前端传过来的数据

技术分享图片
@PutMapping
    public ResultViewModel updateOneGirl(
            @Valid @RequestBody GirlFormModel girlFormModel,
            BindingResult result
            ) {
        // 01 参数验证
        if (result.hasErrors()) {
            // 0101 存储错误信息的字符串变量
            StringBuffer msgBuffer = new StringBuffer();
            // 0102 错误字段集合
            List<FieldError> fieldErrors = result.getFieldErrors();
            for (FieldError fieldError : fieldErrors) {
                // 0103 获取错误信息
                msgBuffer.append(fieldError.getField() + ":" + fieldError.getDefaultMessage());
            }
            // 0104 抛出错误信息
            throw new GirlException(GirlEnum.PARAM_ERROR.getCode(), msgBuffer.toString());
        }

        // 02 将表单对象转化成数据对象
        GirlModel girlModel = new GirlModel();
        BeanUtils.copyProperties(girlFormModel, girlModel);

        // 03 调用服务层进行更新操作
        Boolean updateResult = girlService.updateGirl(girlModel);
        if (updateResult) {
            return ResultViewModelUtil.success(GirlEnum.UPDATE_SUCCESS.getMessage());
        } else {
            return ResultViewModelUtil.error(GirlEnum.UPDATE_ERROR.getCode(), GirlEnum.UPDATE_ERROR.getMessage());
        }
    }
View Code

 

 3 参数验证注解

  后台单独对接收到的参数进行验证时比较麻烦,springboot项目的web组件集成了hibernate-validator,开发者可以直接使用hibernate-validator提供的注解对数据进行校验,当有一些复杂的参数校验时我们也可以自定义校验注解

  技巧01:接收到的参数默认都是字符串类型的

  坑01:有的注解只能用在String类型的属性上

  3.1 常用的验证注解有

    技术分享图片

    技巧01:@JsonProperty可以实现前端的属性名和后台实体类的属性名不一致问题,例如

      技术分享图片

      代码解释:前端传过来的属性名为nick,后台接收的属性名为nickname

  3.2 使用方法

    直接在表单实体类的属性上面添加相应的注解就可以啦

技术分享图片
package cn.xiangxu.springboottest.model.dataFormModel;


import cn.xiangxu.springboottest.commons.validators.GirlFormIdValidator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;

import javax.validation.constraints.Min;

@Data
public class GirlFormModel {

//    @NotBlank(message = "目标girl的ID不能为空")
//    @NotEmpty(message = "目标girl的ID不能为空哟")
//    @GirlFormIdValidator
    private Integer girlId;



    @Min(value = 123)
    private Integer age;

    private String name;

    private String password;

    @NotEmpty(message = "昵称不能为空")
    @NotBlank(message = "昵称不能为空哟")
    @JsonProperty("nick") //  当前端属性为nick后台接收对象的属性为nickName时可以用@JsonProperty来保持一致
    private String nickname;

    @NotEmpty(message = "地址不能为空")
    @NotBlank(message = "地址不能为空哟")
    private String address;
}
View Code

  3.3 如何使参数校验生效

    3.3.1 在控制层方法的形参前面添加@Valid注解

      技术分享图片

    3.3.2 利用BindingResult对象获取参数错误字段和参数错误信息

       技术分享图片

技术分享图片
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.validation;

import java.beans.PropertyEditor;
import java.util.Map;
import org.springframework.beans.PropertyEditorRegistry;

public interface BindingResult extends Errors {
    String MODEL_KEY_PREFIX = BindingResult.class.getName() + ".";

    Object getTarget();

    Map<String, Object> getModel();

    Object getRawFieldValue(String var1);

    PropertyEditor findEditor(String var1, Class<?> var2);

    PropertyEditorRegistry getPropertyEditorRegistry();

    void addError(ObjectError var1);

    String[] resolveMessageCodes(String var1);

    String[] resolveMessageCodes(String var1, String var2);

    void recordSuppressedField(String var1);

    String[] getSuppressedFields();
}
BindingResult源码

       技巧01:利用BindingResult对象的hasErrors方法判断是否有参数错误

    ·  技巧02:利用BindingResult对象的getFieldErrors方法获取所有有参数错误的属性

       技巧03:利用错误属性对象的getDefaultMessage去获取错误提示信息

 

4 自定义参数验证注解

  4.1 定义一个注解接口

    技术分享图片

技术分享图片
package cn.xiangxu.springboottest.commons.validators;

import cn.xiangxu.springboottest.commons.validators.validatorClass.GirlFormValidatorClass;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Constraint(validatedBy = GirlFormValidatorClass.class)
public @interface GirlFormIdValidator {
    String values();
    String message() default "girl的ID必须为纯数字";

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

}
View Code

  4.2 定义一个注解接口实现类

    技巧01:必须实现ConstraintValidator接口

    技术分享图片

技术分享图片
package cn.xiangxu.springboottest.commons.validators.validatorClass;

import cn.xiangxu.springboottest.commons.validators.GirlFormIdValidator;
import cn.xiangxu.springboottest.utils.JudgeUtil;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class GirlFormValidatorClass implements ConstraintValidator<GirlFormIdValidator, Object> {

    private String values;

    @Override
    public void initialize(GirlFormIdValidator girlFormValidator) {
        this.values = girlFormValidator.values();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
        if (JudgeUtil.allIsNumber((String)value)) {
            return true;
        }
        return false;
    }
}
View Code

  4.3 在实体类中使用自定义的参数校验注解

    技术分享图片

 

5 BeanUtils的使用

  利用BeanUtils提供的copyProperties可以实现实体类数据的复制

  坑01:只用属性名和属性类型一致的部分才可以进行复制操作,例如

    BeanUtils.copyProperties(girlFormModel, girlModel);

    代码解释:将girlFormModel对象复制给girlModel对象

技术分享图片
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.beans;

import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

public abstract class BeanUtils {
    private static final Log logger = LogFactory.getLog(BeanUtils.class);
    private static final Set<Class<?>> unknownEditorTypes = Collections.newSetFromMap(new ConcurrentReferenceHashMap(64));

    public BeanUtils() {
    }

    public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
        Assert.notNull(clazz, "Class must not be null");
        if (clazz.isInterface()) {
            throw new BeanInstantiationException(clazz, "Specified class is an interface");
        } else {
            try {
                return clazz.newInstance();
            } catch (InstantiationException var2) {
                throw new BeanInstantiationException(clazz, "Is it an abstract class?", var2);
            } catch (IllegalAccessException var3) {
                throw new BeanInstantiationException(clazz, "Is the constructor accessible?", var3);
            }
        }
    }

    public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
        Assert.notNull(clazz, "Class must not be null");
        if (clazz.isInterface()) {
            throw new BeanInstantiationException(clazz, "Specified class is an interface");
        } else {
            try {
                return instantiateClass(clazz.getDeclaredConstructor());
            } catch (NoSuchMethodException var2) {
                throw new BeanInstantiationException(clazz, "No default constructor found", var2);
            }
        }
    }

    public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) throws BeanInstantiationException {
        Assert.isAssignable(assignableTo, clazz);
        return instantiateClass(clazz);
    }

    public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
        Assert.notNull(ctor, "Constructor must not be null");

        try {
            ReflectionUtils.makeAccessible(ctor);
            return ctor.newInstance(args);
        } catch (InstantiationException var3) {
            throw new BeanInstantiationException(ctor, "Is it an abstract class?", var3);
        } catch (IllegalAccessException var4) {
            throw new BeanInstantiationException(ctor, "Is the constructor accessible?", var4);
        } catch (IllegalArgumentException var5) {
            throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", var5);
        } catch (InvocationTargetException var6) {
            throw new BeanInstantiationException(ctor, "Constructor threw exception", var6.getTargetException());
        }
    }

    public static Method findMethod(Class<?> clazz, String methodName, Class... paramTypes) {
        try {
            return clazz.getMethod(methodName, paramTypes);
        } catch (NoSuchMethodException var4) {
            return findDeclaredMethod(clazz, methodName, paramTypes);
        }
    }

    public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class... paramTypes) {
        try {
            return clazz.getDeclaredMethod(methodName, paramTypes);
        } catch (NoSuchMethodException var4) {
            return clazz.getSuperclass() != null ? findDeclaredMethod(clazz.getSuperclass(), methodName, paramTypes) : null;
        }
    }

    public static Method findMethodWithMinimalParameters(Class<?> clazz, String methodName) throws IllegalArgumentException {
        Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName);
        if (targetMethod == null) {
            targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName);
        }

        return targetMethod;
    }

    public static Method findDeclaredMethodWithMinimalParameters(Class<?> clazz, String methodName) throws IllegalArgumentException {
        Method targetMethod = findMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);
        if (targetMethod == null && clazz.getSuperclass() != null) {
            targetMethod = findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName);
        }

        return targetMethod;
    }

    public static Method findMethodWithMinimalParameters(Method[] methods, String methodName) throws IllegalArgumentException {
        Method targetMethod = null;
        int numMethodsFoundWithCurrentMinimumArgs = 0;
        Method[] var4 = methods;
        int var5 = methods.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            Method method = var4[var6];
            if (method.getName().equals(methodName)) {
                int numParams = method.getParameterTypes().length;
                if (targetMethod != null && numParams >= targetMethod.getParameterTypes().length) {
                    if (!method.isBridge() && targetMethod.getParameterTypes().length == numParams) {
                        if (targetMethod.isBridge()) {
                            targetMethod = method;
                        } else {
                            ++numMethodsFoundWithCurrentMinimumArgs;
                        }
                    }
                } else {
                    targetMethod = method;
                    numMethodsFoundWithCurrentMinimumArgs = 1;
                }
            }
        }

        if (numMethodsFoundWithCurrentMinimumArgs > 1) {
            throw new IllegalArgumentException("Cannot resolve method ‘" + methodName + "‘ to a unique method. Attempted to resolve to overloaded method with the least number of parameters but there were " + numMethodsFoundWithCurrentMinimumArgs + " candidates.");
        } else {
            return targetMethod;
        }
    }

    public static Method resolveSignature(String signature, Class<?> clazz) {
        Assert.hasText(signature, "‘signature‘ must not be empty");
        Assert.notNull(clazz, "Class must not be null");
        int firstParen = signature.indexOf("(");
        int lastParen = signature.indexOf(")");
        if (firstParen > -1 && lastParen == -1) {
            throw new IllegalArgumentException("Invalid method signature ‘" + signature + "‘: expected closing ‘)‘ for args list");
        } else if (lastParen > -1 && firstParen == -1) {
            throw new IllegalArgumentException("Invalid method signature ‘" + signature + "‘: expected opening ‘(‘ for args list");
        } else if (firstParen == -1 && lastParen == -1) {
            return findMethodWithMinimalParameters(clazz, signature);
        } else {
            String methodName = signature.substring(0, firstParen);
            String[] parameterTypeNames = StringUtils.commaDelimitedListToStringArray(signature.substring(firstParen + 1, lastParen));
            Class<?>[] parameterTypes = new Class[parameterTypeNames.length];

            for(int i = 0; i < parameterTypeNames.length; ++i) {
                String parameterTypeName = parameterTypeNames[i].trim();

                try {
                    parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader());
                } catch (Throwable var10) {
                    throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" + parameterTypeName + "] for argument " + i + ". Root cause: " + var10);
                }
            }

            return findMethod(clazz, methodName, parameterTypes);
        }
    }

    public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws BeansException {
        CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);
        return cr.getPropertyDescriptors();
    }

    public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName) throws BeansException {
        CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);
        return cr.getPropertyDescriptor(propertyName);
    }

    public static PropertyDescriptor findPropertyForMethod(Method method) throws BeansException {
        return findPropertyForMethod(method, method.getDeclaringClass());
    }

    public static PropertyDescriptor findPropertyForMethod(Method method, Class<?> clazz) throws BeansException {
        Assert.notNull(method, "Method must not be null");
        PropertyDescriptor[] pds = getPropertyDescriptors(clazz);
        PropertyDescriptor[] var3 = pds;
        int var4 = pds.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            PropertyDescriptor pd = var3[var5];
            if (method.equals(pd.getReadMethod()) || method.equals(pd.getWriteMethod())) {
                return pd;
            }
        }

        return null;
    }

    public static PropertyEditor findEditorByConvention(Class<?> targetType) {
        if (targetType != null && !targetType.isArray() && !unknownEditorTypes.contains(targetType)) {
            ClassLoader cl = targetType.getClassLoader();
            if (cl == null) {
                try {
                    cl = ClassLoader.getSystemClassLoader();
                    if (cl == null) {
                        return null;
                    }
                } catch (Throwable var5) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Could not access system ClassLoader: " + var5);
                    }

                    return null;
                }
            }

            String editorName = targetType.getName() + "Editor";

            try {
                Class<?> editorClass = cl.loadClass(editorName);
                if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Editor class [" + editorName + "] does not implement [java.beans.PropertyEditor] interface");
                    }

                    unknownEditorTypes.add(targetType);
                    return null;
                } else {
                    return (PropertyEditor)instantiateClass(editorClass);
                }
            } catch (ClassNotFoundException var4) {
                if (logger.isDebugEnabled()) {
                    logger.debug("No property editor [" + editorName + "] found for type " + targetType.getName() + " according to ‘Editor‘ suffix convention");
                }

                unknownEditorTypes.add(targetType);
                return null;
            }
        } else {
            return null;
        }
    }

    public static Class<?> findPropertyType(String propertyName, Class... beanClasses) {
        if (beanClasses != null) {
            Class[] var2 = beanClasses;
            int var3 = beanClasses.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                Class<?> beanClass = var2[var4];
                PropertyDescriptor pd = getPropertyDescriptor(beanClass, propertyName);
                if (pd != null) {
                    return pd.getPropertyType();
                }
            }
        }

        return Object.class;
    }

    public static MethodParameter getWriteMethodParameter(PropertyDescriptor pd) {
        return pd instanceof GenericTypeAwarePropertyDescriptor ? new MethodParameter(((GenericTypeAwarePropertyDescriptor)pd).getWriteMethodParameter()) : new MethodParameter(pd.getWriteMethod(), 0);
    }

    public static boolean isSimpleProperty(Class<?> clazz) {
        Assert.notNull(clazz, "Class must not be null");
        return isSimpleValueType(clazz) || clazz.isArray() && isSimpleValueType(clazz.getComponentType());
    }

    public static boolean isSimpleValueType(Class<?> clazz) {
        return ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.isEnum() || CharSequence.class.isAssignableFrom(clazz) || Number.class.isAssignableFrom(clazz) || Date.class.isAssignableFrom(clazz) || URI.class == clazz || URL.class == clazz || Locale.class == clazz || Class.class == clazz;
    }

    public static void copyProperties(Object source, Object target) throws BeansException {
        copyProperties(source, target, (Class)null, (String[])null);
    }

    public static void copyProperties(Object source, Object target, Class<?> editable) throws BeansException {
        copyProperties(source, target, editable, (String[])null);
    }

    public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {
        copyProperties(source, target, (Class)null, ignoreProperties);
    }

    private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties) throws BeansException {
        Assert.notNull(source, "Source must not be null");
        Assert.notNull(target, "Target must not be null");
        Class<?> actualEditable = target.getClass();
        if (editable != null) {
            if (!editable.isInstance(target)) {
                throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");
            }

            actualEditable = editable;
        }

        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
        List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
        PropertyDescriptor[] var7 = targetPds;
        int var8 = targetPds.length;

        for(int var9 = 0; var9 < var8; ++var9) {
            PropertyDescriptor targetPd = var7[var9];
            Method writeMethod = targetPd.getWriteMethod();
            if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
                PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
                if (sourcePd != null) {
                    Method readMethod = sourcePd.getReadMethod();
                    if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
                        try {
                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                readMethod.setAccessible(true);
                            }

                            Object value = readMethod.invoke(source);
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }

                            writeMethod.invoke(target, value);
                        } catch (Throwable var15) {
                            throw new FatalBeanException("Could not copy property ‘" + targetPd.getName() + "‘ from source to target", var15);
                        }
                    }
                }
            }
        }

    }
}
BeanUtils源代码

 

SpringBoot08 请求方式、参数获取注解、参数验证、前后台属性名不一致问题、自定义参数验证注解、BeanUtils的使用

标签:data   get   chm   hash   initial   ati   amp   apach   prefix   

原文地址:https://www.cnblogs.com/NeverCtrl-C/p/8185576.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!