背景:曾经遇到一个很麻烦的事情,就是一个json串中有很多占位符,需要替换成特定文案。如果将json转换成对象后,在一个一个属性去转换的话就出出现很多冗余代码,不美观也不是很实用。

而且也不能提前在json串中替换,因为替换的文案会因为某些变量发生改变。就比如国际化,在中文的时候应该是"你好",而在英文的时候要出现"Hello"。

所以我想到一个方法,为什么不能再json反序列化的时候,把这些都做好呢?

以下的代码介绍的是,我自己扩展的一点点fastjson代码,增加了在反序列化的时候可以对所有的值进行修改的方案。

注意:这个方案会对fastjson反序列化的速度有一定的影响,我只是用来做配置的反序列化,完成后将反序列化的东西缓存起来使用。

使用方式有两种

一种是直接通过 @JsonDeserializer 注解的valueMutators属性注入这种方式有个缺陷,你的修改器必须有无参构造函数的 

@JsonDeserializer(valueMutators = {CoustomizeValueMutator.class})
@Getter
@Setter
public class User { private String name;
...
}

第二种方式是通过直接创建的方式,使用反序列化工具,这种方式支持有参构造函数。

        CoustomizeValueMutator zhCoustomizeValueMutator = new CoustomizeValueMutator(zh);
User user = CustomizeJSON.parseObject(userStr, User.class, zhCoustomizeValueMutator);

下面先展示一下使用效果,测试代码如下:

import com.alibaba.fastjson.parser.deserializer.CustomizeJSON;
import com.raiden.model.*;
import org.junit.jupiter.api.Test; import java.util.*; /**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 22:39 2020/1/28
* @Modified By:
*/
public class AppTest { @Test
public void testFastJosn() throws Throwable {
String userStr = "{\n" +
"\t\"id\":\"I18nKey:20200411001\",\n" +
"\t\"a\":\"I18nKey:张三\",\n" +
"\t\"student\":\"I18nKey:高三三班\",\n" +
"\t\"contents\":[\"I18nKey:1\",\"I18nKey:2\"]\n" +
"}";
Map<String, String> en = new HashMap<>();
en.put("3", "zhangsan");
en.put("4", "20200411001");
en.put("5", "Class three in grade three");
en.put("1", "Hello");
en.put("2", "Welcome home");
Map<String, String> zh = new HashMap<>();
zh.put("3", "张三");
zh.put("4", "20200411001");
zh.put("5", "高三三班");
zh.put("1", "你好");
zh.put("2", "欢迎回家");
CoustomizeValueMutator zhCoustomizeValueMutator = new CoustomizeValueMutator(zh); User user = CustomizeJSON.parseObject(userStr, User.class, zhCoustomizeValueMutator);
System.err.println(user);
String string = "{\n" +
"\t\"users\": [{\n" +
"\t\t\"id\": \"I18nKey:4\",\n" +
"\t\t\"a\": \"I18nKey:3\",\n" +
"\t\t\"student\": \"I18nKey:5\",\n" +
"\t\t\"url\": \"www.baidu.com\",\n" +
"\t\t\"contents\": [\"I18nKey:1\", \"I18nKey:2\"]\n" +
"\t}],\n" +
"\t\"memberId\":\"2020\"\n" +
"}";
CoustomizeValueMutator enCoustomizeValueMutator = new CoustomizeValueMutator(en);
Administration administration = CustomizeJSON.parseObject(string, Administration.class, enCoustomizeValueMutator);
System.err.println(administration);
}
}

运行效果:

 下面是测试模型代码:

import com.alibaba.fastjson.parser.deserializer.JsonDeserializer;
import com.raiden.CoustomizeValueMutator;
import lombok.Getter;
import lombok.Setter; import java.util.List; /**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 23:56 2020/4/17
* @Modified By:
*/
@JsonDeserializer
@Getter
@Setter
public class Administration { private List<User> users;
private String memberId; @Override
public String toString() {
return "Administration{" +
"users=" + users +
", memberId='" + memberId + '\'' +
'}';
}
}
import com.alibaba.fastjson.parser.deserializer.JsonDeserializer;
import lombok.Getter;
import lombok.Setter; import java.util.List; /**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 15:53 2020/3/21
* @Modified By:
*/
@JsonDeserializer
@Getter
@Setter
public class User { private String name;
private String id;
private String student;
private List<String> contents;
private String url; @Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
", student='" + student + '\'' +
", contents='" + contents.toString() + '\'' +
", url='" + url + '\'' +
'}';
}
}

自定义的反序列化值修改器:

import com.alibaba.fastjson.parser.deserializer.DeserializerValueMutator;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; /**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 22:15 2020/5/1
* @Modified By:
*/
public class CoustomizeValueMutator implements DeserializerValueMutator { private Map<String, String> dataSource; public CoustomizeValueMutator(Map<String, String> dataSource){
this.dataSource = dataSource;
}
@Override
public Object process(Object object, Annotation[] annotations, String name, Object value) {
if (value instanceof List){
List list = new ArrayList();
for (Object o : (List) value){
if (!(o instanceof String)){
return value;
}
list.add(DeserializerUtils.deserializer(o, dataSource));
}
return list;
}
return DeserializerUtils.deserializer(value, dataSource);
}
}

一些工具类和静态资源类:

/**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 23:00 2020/4/17
* @Modified By:
*/
public class CustomizeStaticConfig {
public static final String I18N_KEY = "I18nKey:";
}
import org.apache.commons.lang3.StringUtils;

import java.util.Map;

/**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 0:15 2020/4/18
* @Modified By:
*/
public final class DeserializerUtils { public static final Object deserializer(Object value, Map<String, String> languageConfig){
String result = null;
if (value.getClass() == String.class && StringUtils.contains((result = ((String) value).trim()), CustomizeStaticConfig.I18N_KEY)){
int indexOf = result.indexOf(CustomizeStaticConfig.I18N_KEY) + CustomizeStaticConfig.I18N_KEY.length();
String key = StringUtils.substring(result, indexOf);
return languageConfig.getOrDefault(key, result);
}
return value;
}
}

 下面给出的是扩展的关键代码。

首先是自定义解析配置类,这个类是核心。这个类继承了 com.alibaba.fastjson.parser.ParserConfig 类。覆写了其两个核心方法。

方法一:

createFieldDeserializer(ParserConfig mapping, JavaBeanInfo beanInfo, FieldInfo fieldInfo) 创建一个属性反序列化处理类

该方法的修改,是将源码中的 ArrayListTypeFieldDeserializer 替换成 我们自定义的 CustomizeArrayListTypeFieldDeserializer 处理器。

将源码中的 DefaultFieldDeserializer 替换成 我们自定义的 CustomizeDefaultFieldDeserializer 处理器

方法二:

createJavaBeanDeserializer(Class<?> clazz, Type type)  创建一个 JavaBean 反序列化处理器

新增判断逻辑,如果要反序列化的类上存在 @JsonDeserializer 标识注解,返回包含自定义配置类的 JavaBeanDeserializer。

import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.FieldInfo;
import com.alibaba.fastjson.util.JavaBeanInfo; import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
/**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 21:52 2020/4/17
* @Modified By: 自定义fastjson 解析配置类 这个类是核心
*/
public class CustomizeParserConfig extends ParserConfig { /**
* 值修改器数组 可以将类修改器放入其中使用
*/
private DeserializerValueMutator[] valueMutators; public CustomizeParserConfig(){
} /**
* 有参构造方法 可以通过该方法 将类修改器放入其中
* @param valueMutators
*/
public CustomizeParserConfig(DeserializerValueMutator... valueMutators){
super();
this.valueMutators = valueMutators;
} /**
* 创建一个属性反序列化处理类
* @param mapping
* @param beanInfo
* @param fieldInfo
* @return
*/
@Override
public FieldDeserializer createFieldDeserializer(ParserConfig mapping, //
JavaBeanInfo beanInfo, //
FieldInfo fieldInfo) {
//获取要反序列化的model 的class
Class<?> clazz = beanInfo.clazz;
//获取要反序列化属性的 class
Class<?> fieldClass = fieldInfo.fieldClass; Class<?> deserializeUsing = null;
JSONField annotation = fieldInfo.getAnnotation();
if (annotation != null) {
deserializeUsing = annotation.deserializeUsing();
if (deserializeUsing == Void.class) {
deserializeUsing = null;
}
} if (deserializeUsing == null && (fieldClass == List.class || fieldClass == ArrayList.class)) {
//将源码中的 ArrayListTypeFieldDeserializer 替换成 我们自定义的 CustomizeArrayListTypeFieldDeserializer 处理器
return new CustomizeArrayListTypeFieldDeserializer(clazz, fieldInfo, valueMutators);
}
//将源码中的 DefaultFieldDeserializer 替换成 我们自定义的 CustomizeDefaultFieldDeserializer 处理器
return new CustomizeDefaultFieldDeserializer(mapping, clazz, fieldInfo, valueMutators);
} /**
* 创建一个 javaBean 反序列化处理器
* @param clazz
* @param type
* @return
*/
@Override
public ObjectDeserializer createJavaBeanDeserializer(Class<?> clazz, Type type) {
//获取要反序列化类上的标识注解
JsonDeserializer jsonDeserializer = clazz.getAnnotation(JsonDeserializer.class);
//如果不存在就走原逻辑
if (jsonDeserializer != null){
//获取注解中的反序列化值处理器
Class<? extends DeserializerValueMutator>[] classes = jsonDeserializer.valueMutators();
if (classes != null && classes.length > 0){
DeserializerValueMutator[] mutators = new DeserializerValueMutator[classes.length];
int size = 0;
for (Class<? extends DeserializerValueMutator> c : classes) {
try {
DeserializerValueMutator mutator = c.newInstance();
mutators[size] = mutator;
size++;
} catch (Exception e) {
//如果创建失败了就忽略掉这次错误
}
}
if (size > 0){
//判断原来是否有值 如果有 就合并成一组
if (valueMutators != null){
DeserializerValueMutator[] newValueMutators = new DeserializerValueMutator[size + valueMutators.length];
System.arraycopy(valueMutators, 0, newValueMutators, 0, valueMutators.length);
System.arraycopy(mutators, 0, newValueMutators, valueMutators.length, size);
this.valueMutators = newValueMutators;
}else {
this.valueMutators = new DeserializerValueMutator[size];
System.arraycopy(mutators, 0, valueMutators, 0, size);
}
}
}
if (valueMutators != null){
return new JavaBeanDeserializer(this, clazz);
}
}
return super.createJavaBeanDeserializer(clazz, type);
}
}

 CustomizeDefaultFieldDeserializer 类继承了 DefaultFieldDeserializer 类在构造方法中新增了参数 valueMutators(值修改器数组)

并在 public void setValue(Object object, Object value) 方法中新增了逻辑如果值修改器数组中存在值修改器,就遍历所有的修改器,

依次调用修改器的 process方法修改值。

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.FieldInfo; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; /**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 0:13 2020/4/18
* @Modified By: 替代fastjson中 对象反序列化处理类
*/
public class CustomizeDefaultFieldDeserializer extends DefaultFieldDeserializer { private DeserializerValueMutator[] valueMutators; public CustomizeDefaultFieldDeserializer(ParserConfig config, Class<?> clazz, FieldInfo fieldInfo,DeserializerValueMutator[] valueMutators) {
super(config, clazz, fieldInfo);
this.valueMutators = valueMutators;
} public void setValue(Object object, Object value) {
if (value == null //
&& fieldInfo.fieldClass.isPrimitive()) {
return;
} else if (fieldInfo.fieldClass == String.class
&& fieldInfo.format != null
&& fieldInfo.format.equals("trim")){
value = ((String) value).trim();
}
try {
/**
* 如果值修改器数组中存在值修改器实例,就遍历该数组,依次调用所有的修改器的 process方法
*/
if (valueMutators != null && valueMutators.length > 0){
for (DeserializerValueMutator mutator : valueMutators){
value = mutator.process(object,fieldInfo.field.getAnnotations(), fieldInfo.name, value);
}
}
Method method = fieldInfo.method;
if (method != null) {
if (fieldInfo.getOnly) {
if (fieldInfo.fieldClass == AtomicInteger.class) {
AtomicInteger atomic = (AtomicInteger) method.invoke(object);
if (atomic != null) {
atomic.set(((AtomicInteger) value).get());
}
} else if (fieldInfo.fieldClass == AtomicLong.class) {
AtomicLong atomic = (AtomicLong) method.invoke(object);
if (atomic != null) {
atomic.set(((AtomicLong) value).get());
}
} else if (fieldInfo.fieldClass == AtomicBoolean.class) {
AtomicBoolean atomic = (AtomicBoolean) method.invoke(object);
if (atomic != null) {
atomic.set(((AtomicBoolean) value).get());
}
} else if (Map.class.isAssignableFrom(method.getReturnType())) {
Map map = (Map) method.invoke(object);
if (map != null) {
if (map == Collections.emptyMap()
|| map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
// skip
return;
} map.putAll((Map) value);
}
} else {
Collection collection = (Collection) method.invoke(object);
if (collection != null && value != null) {
if (collection == Collections.emptySet()
|| collection == Collections.emptyList()
|| collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
// skip
return;
} collection.clear();
collection.addAll((Collection) value);
}
}
} else {
method.invoke(object, value);
}
} else {
final Field field = fieldInfo.field; if (fieldInfo.getOnly) {
if (fieldInfo.fieldClass == AtomicInteger.class) {
AtomicInteger atomic = (AtomicInteger) field.get(object);
if (atomic != null) {
atomic.set(((AtomicInteger) value).get());
}
} else if (fieldInfo.fieldClass == AtomicLong.class) {
AtomicLong atomic = (AtomicLong) field.get(object);
if (atomic != null) {
atomic.set(((AtomicLong) value).get());
}
} else if (fieldInfo.fieldClass == AtomicBoolean.class) {
AtomicBoolean atomic = (AtomicBoolean) field.get(object);
if (atomic != null) {
atomic.set(((AtomicBoolean) value).get());
}
} else if (Map.class.isAssignableFrom(fieldInfo.fieldClass)) {
Map map = (Map) field.get(object);
if (map != null) {
if (map == Collections.emptyMap()
|| map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
// skip
return;
}
map.putAll((Map) value);
}
} else {
Collection collection = (Collection) field.get(object);
if (collection != null && value != null) {
if (collection == Collections.emptySet()
|| collection == Collections.emptyList()
|| collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
// skip
return;
} collection.clear();
collection.addAll((Collection) value);
}
}
} else {
if (field != null) {
field.set(object, value);
}
}
}
} catch (Exception e) {
throw new JSONException("set property error, " + clazz.getName() + "#" + fieldInfo.name, e);
}
}
}

类CustomizeArrayListTypeFieldDeserializer 和 类CustomizeDefaultFieldDeserializer 改动类似。

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.FieldInfo; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; /**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 0:13 2020/4/18
* @Modified By: 替代fastjson中 对象反序列化处理类
*/
public class CustomizeDefaultFieldDeserializer extends DefaultFieldDeserializer { private DeserializerValueMutator[] valueMutators; public CustomizeDefaultFieldDeserializer(ParserConfig config, Class<?> clazz, FieldInfo fieldInfo,DeserializerValueMutator[] valueMutators) {
super(config, clazz, fieldInfo);
this.valueMutators = valueMutators;
} public void setValue(Object object, Object value) {
if (value == null //
&& fieldInfo.fieldClass.isPrimitive()) {
return;
} else if (fieldInfo.fieldClass == String.class
&& fieldInfo.format != null
&& fieldInfo.format.equals("trim")){
value = ((String) value).trim();
}
try {
/**
* 如果值修改器数组中存在值修改器实例,就遍历该数组,依次调用所有的修改器的 process方法
*/
if (valueMutators != null && valueMutators.length > 0){
for (DeserializerValueMutator mutator : valueMutators){
value = mutator.process(object,fieldInfo.field.getAnnotations(), fieldInfo.name, value);
}
}
Method method = fieldInfo.method;
if (method != null) {
if (fieldInfo.getOnly) {
if (fieldInfo.fieldClass == AtomicInteger.class) {
AtomicInteger atomic = (AtomicInteger) method.invoke(object);
if (atomic != null) {
atomic.set(((AtomicInteger) value).get());
}
} else if (fieldInfo.fieldClass == AtomicLong.class) {
AtomicLong atomic = (AtomicLong) method.invoke(object);
if (atomic != null) {
atomic.set(((AtomicLong) value).get());
}
} else if (fieldInfo.fieldClass == AtomicBoolean.class) {
AtomicBoolean atomic = (AtomicBoolean) method.invoke(object);
if (atomic != null) {
atomic.set(((AtomicBoolean) value).get());
}
} else if (Map.class.isAssignableFrom(method.getReturnType())) {
Map map = (Map) method.invoke(object);
if (map != null) {
if (map == Collections.emptyMap()
|| map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
// skip
return;
} map.putAll((Map) value);
}
} else {
Collection collection = (Collection) method.invoke(object);
if (collection != null && value != null) {
if (collection == Collections.emptySet()
|| collection == Collections.emptyList()
|| collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
// skip
return;
} collection.clear();
collection.addAll((Collection) value);
}
}
} else {
method.invoke(object, value);
}
} else {
final Field field = fieldInfo.field; if (fieldInfo.getOnly) {
if (fieldInfo.fieldClass == AtomicInteger.class) {
AtomicInteger atomic = (AtomicInteger) field.get(object);
if (atomic != null) {
atomic.set(((AtomicInteger) value).get());
}
} else if (fieldInfo.fieldClass == AtomicLong.class) {
AtomicLong atomic = (AtomicLong) field.get(object);
if (atomic != null) {
atomic.set(((AtomicLong) value).get());
}
} else if (fieldInfo.fieldClass == AtomicBoolean.class) {
AtomicBoolean atomic = (AtomicBoolean) field.get(object);
if (atomic != null) {
atomic.set(((AtomicBoolean) value).get());
}
} else if (Map.class.isAssignableFrom(fieldInfo.fieldClass)) {
Map map = (Map) field.get(object);
if (map != null) {
if (map == Collections.emptyMap()
|| map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
// skip
return;
}
map.putAll((Map) value);
}
} else {
Collection collection = (Collection) field.get(object);
if (collection != null && value != null) {
if (collection == Collections.emptySet()
|| collection == Collections.emptyList()
|| collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
// skip
return;
} collection.clear();
collection.addAll((Collection) value);
}
}
} else {
if (field != null) {
field.set(object, value);
}
}
}
} catch (Exception e) {
throw new JSONException("set property error, " + clazz.getName() + "#" + fieldInfo.name, e);
}
}
}

下面是值修改器接口定义:

import java.lang.annotation.Annotation;

/**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 22:01 2020/5/1
* @Modified By: 反序列化值修改器接口
*/
public interface DeserializerValueMutator { Object process(Object object, Annotation[] annotations, String name, Object value);
}

反序列化标识注解,只有用这个注解注释的类才会执行拓展的方法。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 22:25 2020/4/17
* @Modified By: 反序列化值修改标识注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface JsonDeserializer {
/**
* 注意这里只能放无参构造函数的修改器 否则会创建失败
* @return
*/
Class<? extends DeserializerValueMutator>[] valueMutators() default {};
}

强化的JSON序列化工具类:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature; import java.lang.reflect.Type; /**
* @创建人:Raiden
* @Descriotion:
* @Date:Created in 22:12 2020/5/1
* @Modified By: 反序列化工具类
*/
public final class CustomizeJSON { public static <T> T parseObject(String input,Type clazz,DeserializerValueMutator... valueMutators) {
return JSON.parseObject(input, clazz, new CustomizeParserConfig(valueMutators));
} public static <T> T parseObject(String json, Type type,DeserializerValueMutator[] valueMutators, Feature... features) {
return JSON.parseObject(json, type, new CustomizeParserConfig(valueMutators), features);
} public static <T> T parseObject(String json, Type type,Feature... features) {
return JSON.parseObject(json, type, new CustomizeParserConfig(), features);
} public static <T> T parseObject(String json, Type type) {
return JSON.parseObject(json, type, new CustomizeParserConfig());
}
}

以上代码都可以在我的git中下载:https://github.com/RaidenXin/fastjson-deserializer.git

创作不易,如果转载请注明出处,小编在此感谢各位看官。

如果觉得有用,请看官们点个赞,谢谢。

如果有想学Redis的可以关注我的Redis文章系列:

小白也能看懂的REDIS教学基础篇——REDIS基础数据结构

小白也能看懂的REDIS教学基础篇——朋友面试被SKIPLIST跳跃表拦住了

记录一次源码扩展案列——FastJson自定义反序列化ValueMutator的更多相关文章

  1. storm源码之巧用java反射反序列化clojure的defrecord获取属性值

    [原创]storm源码之巧用java反射反序列化clojure的defrecord获取属性值 [原创]storm源码之巧用java反射反序列化clojure的defrecord获取属性值 storm源 ...

  2. springboot aop 自定义注解方式实现一套完善的日志记录(完整源码)

    https://www.cnblogs.com/wenjunwei/p/9639909.html https://blog.csdn.net/tyrant_800/article/details/78 ...

  3. Linux下利用phpize安装memcashe的php源码扩展包

    phpize是php的一种构建工具,为PHP扩展准备构建环境,通过phpize可以编译php的扩展源码文件为php扩展模块. 一.安装 phpize工具可以通过安装php-dev包自动集成安装.安装完 ...

  4. 记录编译JDK11源码时遇到的两个问题

    执行make all报错信息: 错误一 /src/hotspot/share/runtime/arguments.cpp:1461:35: error: result of comparison ag ...

  5. 四:WEB源码扩展

    前言:WEB源码在安全测试中是非常重要的信息来源,可以用来进行代码审计漏洞也可以用来做信息突破口,其中WEB源码有很多技术需要简明分析,获取某ASP源码后就可以采用默认数据库下载为突破,获取某其他脚本 ...

  6. [Abp vNext 源码分析] - 11. 用户的自定义参数与配置

    一.简要说明 文章信息: 基于的 ABP vNext 版本:1.0.0 创作日期:2019 年 10 月 23 日晚 更新日期:暂无 ABP vNext 针对用户可编辑的配置,提供了单独的 Volo. ...

  7. Spring源码阅读笔记05:自定义xml标签解析

    在上篇文章中,提到了在Spring中存在默认标签与自定义标签两种,并且详细分析了默认标签的解析,本文就来分析自定义标签的解析,像Spring中的AOP就是通过自定义标签来进行配置的,这里也是为后面学习 ...

  8. HTML5游戏源码 飞翔的字母 可自定义内容

    相信大家都玩过飞翔的小鸟吧,当然,可能已经有很多人因为这个游戏砸了不少手机.吼吼. 废话不多说,回到主题,源码如下. 博客园上传空间大小有限制,没法上传了,需要打包源码的朋友们请留言邮箱地址.当然还有 ...

  9. Dubbo源码-Dubbo是如何随心所欲自定义XML标签的

    叨叨 今天考虑了很久要不要写这篇文章. 距离<Dubbo源码>系列的开篇到现在已经快两个月时间了.当时是想着工作上的RPC框架使用存在一些让人头疼的问题,就来看看Dubbo给出了一套什么样 ...

随机推荐

  1. 用于测试 JsonAnalyzer2 1.01版的测试用例

    14. 原文={"animal":"ca,t","color":"ora:nge","isMale" ...

  2. 求支付表中按id累积和最接近100的那条记录

    此例源自美团的一道SQL面试题 支付表结构: create table hy_payment( id number(4,0) primary key, pay number(3,0) not null ...

  3. 一个极简Jsp工程下载

    下载地址:https://files.cnblogs.com/files/xiandedanteng/SimpleJspWebApp20191227.zip 要得到war文件,右键点项目->Ex ...

  4. MySQL查询point类型类型的坐标,返回经度纬度

    location字段为point类型的空间坐标 SELECT id, name, address, x(location) as 经度, Y(location) as 纬度, ROUND( 6378. ...

  5. 出现jupyter notebook password or token提示需要token的处理方法

    很多朋友不知道下面的情况怎么处理,我给大家介绍一个方法! 出现这种情况很简单用下面这个地址就能进去了 (注意是你自己的 不是我这个)

  6. oracle之网络

    Oracle 网络 sqlplus sys/123123@192.168.143.90:1521/urpdb as sysdba 15.1 Oracle Net 基本要素: 15.1.1 服务器端的l ...

  7. hystrix源码小贴士之调用异常处理

    executeCommandAndObserve方法处理onerror异常. return execution.doOnNext(markEmits) .doOnCompleted(markOnCom ...

  8. 【知识分享】Navicat Premium for Mac的破解教程

    转自Navicat Premium for Mac v12.0.22.0 破解教程,macOS上手动破解,无需补丁,无毒下载了Navicat,没有注册码,突然发现了这篇破解教程,竟爱不释手,顾Copy ...

  9. 深入理解SVM,详解SMO算法

    今天是机器学习专题第35篇文章,我们继续SVM模型的原理,今天我们来讲解的是SMO算法. 公式回顾 在之前的文章当中我们对硬间隔以及软间隔问题都进行了分析和公式推导,我们发现软间隔和硬间隔的形式非常接 ...

  10. windows服务器添加磁盘后,提示The disk is offline because of policy set by an administrator的解决办法

    操作系统:Windows Server 2008 R2 Enterprise 事件:存储在虚拟机上添加三块磁盘,笔者准备扩展到E盘(动态分区) 问题:存储团队添加磁盘后,OS的磁盘管理界面,看到提示, ...