SpringBoot08 请求方式、参数获取注解、参数验证、前后台属性名不一致问题、自定义参数验证注解、BeanUtils的使用
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));
}
2.1.1 为路径参数添加正则表达式
如果前端请求的url中的路径参数不满足正则表达式时,请求就会失败;错误信息是找不到相应的请求方法
代码解释:路径参数必须是数字类型,否则就不会匹配到这个请求路径,如果不是数字类型时返回给前端的信息如下:
2.2 @RequestParam
用来获取多个参数,常用语POST、PUT操作
技巧01:这种参数时通过请求rul进行传递的,请求url中?后面的参数就是这种类型
技巧02:默认就是利用这种方式进行传参
技巧03:controller中方法参数可以利用一个对象来接收前端传过来的参数
2.3 @RequestBody
利用一个对象去获取前端传过来的数据
技巧01:这种参数是通过请求体进行传递的
@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());
}
}
3 参数验证注解
后台单独对接收到的参数进行验证时比较麻烦,springboot项目的web组件集成了hibernate-validator,开发者可以直接使用hibernate-validator提供的注解对数据进行校验,当有一些复杂的参数校验时我们也可以自定义校验注解
技巧01:接收到的参数默认都是字符串类型的
技巧02:如果是SpringBoot项目必须导入JPA先关的jar包,因为JPA是基于Hibernate的,所以JPA相关的jar包里面会有相关的验证注解;其实不用导入JPA的jar包也可以使用,因为 spring-boot-starter-web 中已经包含了 hibernate-validator 相关的校验注解。
坑01:有的注解只能用在String类型的属性上
3.1 常用的验证注解有
技巧01:@JsonProperty可以实现前端的属性名和后台实体类的属性名不一致问题,例如
代码解释:前端传过来的属性名为nick,后台接收的属性名为nickname
技巧01:前端传过来的参数和后台不一致的情况只对@RequestBody这种参数有效
技巧02:后台传给前台时使用的属性名是@JsonProperty中的参数而不是实体中定义的属性名
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;
}
3.3 如何使参数校验生效
3.3.1 在控制层方法的形参前面添加@Valid注解
技巧01:如果在controller层控制方法中的参数标注了@Valid注解后,前端传过来的参数一旦发现不合法就会抛出请求错误(即:400错误)
3.3.2 利用BindingResult对象获取参数错误字段和参数错误信息
技巧01:如果只是添加@Valid注解,如果参数错误就会直接抛出异常
技巧02:后台开发时通常都需要对前端传过来的参数进行一次参数验证,如果参数不正确我们需要抛出一些用户可以识别的错误信息而不是抛出原生的错误;所以我们需要在方法中添加一个BindingResult参数
技巧03:给控制方法添加了BindingResult参数后,即使前端传过来的参数不合法也会继续执行方法体;我们可以利用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源码
》获取单个错误字段和错误信息的代码如下
@PostMapping(value = "/user")
public String create(
@Valid @RequestBody User user,
BindingResult errors
) {
if (errors.hasErrors()) {
errors.getAllErrors().stream().forEach(
error -> {
FieldError fieldError = (FieldError)error;
log.info("错误字段:{} -> 错误信息:{}",
fieldError.getField(),
fieldError.getDefaultMessage()
);
}
);
} log.info("获取到的参数信息为:" + user);
String info = "新增用户成功";
return info;
}
技巧04:利用BindingResult对象的hasErrors方法判断是否有参数错误
· 技巧05:利用BindingResult对象的getFieldErrors方法获取所有有参数错误的属性
技巧06:利用错误属性对象的getDefaultMessage去获取错误提示信息
4 自定义参数验证注解
4.1 定义一个注解接口
技巧01:每个自定义的校验注解必须要有这四个成员
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 {}; }
4.2 定义一个注解接口实现类
技巧01:必须实现ConstraintValidator接口
技巧02:实现了ConstraintValidator接口后即使不进行Bean配置,spring也会将这个类进行Bean管理
技巧03:可以在实现了ConstraintValidator接口的类中依赖注入其它Bean
技巧04:实现了ConstraintValidator接口后必须重写 initialize 和 isValid 这两个方法;initialize方法主要来进行初始化,通常用来获取自定义注解的属性值;isValid 方法主要进行校验逻辑,返回true表示校验通过,返回false表示校验失败,通常根据注解属性值和实体类属性值进行校验判断
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;
}
}
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源代码
·下面是我的公众号二维码,欢迎关注·
尋渝記
微信号:xyj_fury
SpringBoot08 请求方式、参数获取注解、参数验证、前后台属性名不一致问题、自定义参数验证注解、BeanUtils的使用的更多相关文章
- SpringBoot学习笔记(七):SpringBoot使用AOP统一处理请求日志、SpringBoot定时任务@Scheduled、SpringBoot异步调用Async、自定义参数
SpringBoot使用AOP统一处理请求日志 这里就提到了我们Spring当中的AOP,也就是面向切面编程,今天我们使用AOP去对我们的所有请求进行一个统一处理.首先在pom.xml中引入我们需要的 ...
- java反射获取类的类名、属性名、属性类型、方法、执行方法、构造函数
public class Demo02 { @SuppressWarnings("all") public static void main(String[] args) thro ...
- JMeter学习-011-JMeter 后置处理器实例之 - 正则表达式提取器(三)多参数获取进阶引用篇
前两篇文章分表讲述了 后置处理器 - 正则表达式提取器概述及简单实例.多参数获取,相应博文敬请参阅 简单实例.多参数获取. 此文主要讲述如何引用正则表达式提取器获取的数据信息.其实,正则表达式提取器获 ...
- 【spring springmvc】这里有你想要的SpringMVC的REST风格的四种请求方式
概述 之前的文章springmvc使用注解声明控制器与请求映射有简单提到过控制器与请求映射,这一次就详细讲解一下SpringMVC的REST风格的四种请求方式及其使用方法. 你能get的知识点 1.什 ...
- get、post请求方式在jmeter中使用步骤
jmeter:性能测试工具,压测 一.jmeter工具测试接口时使用步骤: 1.测试计划右键--添加--Threads(Users)--线程组(线程数就是并发数) 2.线程组右键--Sampler-- ...
- Java自定义数据验证注解Annotation
本文转载自:https://www.jianshu.com/p/616924cd07e6 Java注解Annotation用起来很方便,也越来越流行,由于其简单.简练且易于使用等特点,很多开发工具都提 ...
- mybatis——解决属性名和数据库字段名不一致问题(注解方式)
当我们使用注解开发时有时会遇到数据库字段名与实体类属性名不一致的问题.xml方式开发可以通过结果集映射的方式解决,那注解方式开发要怎么解决呢? 注解解决方式: @Results()注解 Results ...
- Scrapy命令行调用传入自定义参数
在做爬虫服务化时,有这样一个需求:接口用命令行启动爬虫,但是数据入库时要记录此次任务的task_id. 简单说就是,Scrapy命令行启动时要动态传参进去. 解决方案: 在spider中定义一个构造函 ...
- webAPI(DOM) 2.1 获取页面元素 | 事件1 | 属性操作 | 节点 | 创建元素 | 事件2
js分三个部分: ECMAScript标准:js的基本语法 DOM:Ducument Object Model--->文档对象模型--->操作页面的元素 BOM:Browser Objec ...
随机推荐
- AJax知识介绍
参考:http://www.runoob.com/ajax/ajax-asp-php.html
- Django下的templates 和 static静态文件
如果Django顶层目录中没有templates的话,就自己新建一个Directory ,这个文件是存放html文件的 1)如果在views里面用render(request,"" ...
- 自行编译mwan加入openwrt里
参考源文:http://www.right.com.cn/forum/thread-124449-1-1.html 本例以 opoenwrt 12.09正式版为例,原软件来自openwrt 英文论坛: ...
- CentOS 7下源码安装zabbix服务
安装环境需要LAMP或者LNMP先搭建好 在此我使用上一篇搭建好的LNMP环境来安装zabbix 1.下载zabbix http://www.zabbix.com/download.php 2.安装及 ...
- Android Studio 打包时 Signature Version 选择V1还是V2 ?
只勾选V2会导致 7.0 以下的安卓机出现 INSTALL_PARSE_FAILED_NO_CERTIFICATES 的问题 ,推荐全选. 解决方案一v1和v2的签名使用1)只勾选v1签名并不会影响什 ...
- JAVAWEB 一一ibatis(框架)
,升级版是mybatis,在配置文件里写sql语句对字段进行CURD) jar包 sqlMapConfig <?xml version="1.0" encoding=&quo ...
- 法门扫地僧总结vue面试题(部分来源网络)
Front-End 前端开发工程师面试宝典! (本文部分有转载,不定期更新!) 前言(README.md) 本仓库是我整理的前端常见面试题,大部分由我整理,其中个别部分参考 ...
- AMQP协议与RabbitMQ、MQ消息队列的应用场景
什么是AMQP? 在异步通讯中,消息不会立刻到达接收方,而是被存放到一个容器中,当满足一定的条件之后,消息会被容器发送给接收方,这个容器即消息队列,而完成这个功能需要双方和容器以及其中的各个组件遵守统 ...
- php图片转base64
/*读取问价家图片生澈哥哥js文件 */header("Access-Control-Allow-Origin: *");$i=0;$handle = opendir('./ima ...
- 自己电脑能ping别人的,但别人电脑去不能跟我们的电脑通信
记住一点:多半时防火墙出了问题. 打开“控制面板”——点击“系统和安全”——“Windows防火墙”——点击“打开或关闭”Windows防火墙--点击家庭组网络或者工作组网络——关闭家庭组和工作组的防 ...