最近有个想法,把一些比较通用的逻辑拆出来放到一个单独的类里面。
举个比较简单的例子就是报表查询的时候,某一查询条件存在多种组合方式和要求,比如数据原本是这样的
{
"list" : [1,2,3,4,5],
"name" : "night",
"user" : 1
}
实际上我们需要调用另外一个方法将其转为
{
"list" : [1,-2,3,-4,5],
"name" : "night",
"user" : 1
}
也就是说要根据业务需要将其中一部分数据进行处理,然后再执行最终的查询
通常这种情况下我们需要直接写代码调用另外一个方法,将数据传进去进行处理,但是这种方式带来的问题就是维护性的下降
如果能有某一个类代表此类的逻辑,前端直接传值到此对象中,他自行进行数据处理,我们只需要直接调用get()方法就能拿到想要的参数就好了
之前在公司的时候简单的尝试了一下,发现list无法直接转为class对象,@JsonDeserialize处理起来很麻烦,于是想着抽象一下,可以直接使用就好了。
经过了半小时的查阅资料,终于解决了这个问题。
首先定义一个基础数据类
@Data
public class MyData<R> {
private List<R> list;
public MyData() {
}
public MyData(List<R> list) {
this.list = list;
}
}
这个类主要用于其他类继承并实现功能
然后就是实现类,这里我直接起名叫部门类,你也可以根据你的业务修改此名称,该类继承上面的mydata类
@Data
@NoArgsConstructor
public class DepartmentIds extends MyData<Long>{
}
接下来就是jackson的序列化类和反序列化类
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class BaseListToObjectDeserializer<T extends MyData,R>{
public JsonDeserializer<T> get(Class<T> t, Function<String,R> strToData){
return new JsonDeserializer<T>() {
@Override
public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
T result = null;
try {
result = t.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
JsonNode node = p.readValueAsTree();
List<R> collect = IntStream.range(0, node.size()).boxed().map(x -> strToData.apply(node.get(x).toString())).collect(Collectors.toList());
result.setList(collect);
return result;
}
};
}
}
序列化类 (由于jackson的writeArray仅支持int,string,long,double四种数组入参,因此就写了四种)
package com.example.springrabbitmq;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
public class BaseListToObjectSerializer<T extends MyData<R>,R> {
public JsonSerializer<T> getInt(Class<T> t, Function<List<R>, int[]> strToData) {
return new JsonSerializer<T>() {
@Override
public void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (Objects.nonNull(value)) {
int[] apply = strToData.apply(value.getList());
gen.writeArray(apply, 0, apply.length);
}
}
};
}
public JsonSerializer<T> getString(Class<T> t, Function<List<R>, String[]> strToData) {
return new JsonSerializer<T>() {
@Override
public void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (Objects.nonNull(value)) {
String[] apply = strToData.apply(value.getList());
gen.writeArray(apply, 0, apply.length);
}
}
};
}
public JsonSerializer<T> getLong(Class<T> t, Function<List<R>, long[]> strToData) {
return new JsonSerializer<T>() {
@Override
public void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (Objects.nonNull(value)) {
long[] apply = strToData.apply(value.getList());
gen.writeArray(apply, 0, apply.length);
}
}
};
}
}
配置spring jackson配置
package com.example.springrabbitmq.config;
import com.example.springrabbitmq.BaseListToObjectDeserializer;
import com.example.springrabbitmq.BaseListToObjectSerializer;
import com.example.springrabbitmq.DepartmentIds;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import java.math.BigInteger;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebSerializerConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder
.serializerByType(Long.class, ToStringSerializer.instance)
.serializerByType(BigInteger.class, ToStringSerializer.instance)
// 这里我们每添加一种mydata实现就需要新增一行类似代码到这里,像这里我的DepartmentIds实际承载的数据是long类型的,因此在getLong中需要传入x -> x.stream().mapToLong(l -> l).toArray())这么一段来转换数据,当然这块还可以再优化一下
.serializerByType(DepartmentIds.class, new BaseListToObjectSerializer<DepartmentIds,Long>().getLong(DepartmentIds.class, x -> x.stream().mapToLong(l -> l).toArray()))
// 反序列化,同上,每新增类型就加一行
.deserializerByType(DepartmentIds.class, new BaseListToObjectDeserializer<DepartmentIds,Long>().get(DepartmentIds.class, Long::valueOf))
;
}
}
调用示例:
@Slf4j
@RestController
@RequestMapping("test")
public class JacksonDemo {
@PostMapping("1")
public Param test(@RequestBody Param param){
log.info("param:{}",param);
Param result = new Param();
BeanUtils.copyProperties(param, result);
return result;
}
}
@Data
public class Param {
private DepartmentIds list;
private String name;
}
curl --request POST \
--url http://127.0.0.1:8080/test/1 \
--header 'Content-Type: application/json' \
--data '{
"list" : [1,2,3,4,5],
"name" : "李华"
}'
可以看到返回结果是这样的,list参数的入参和出参不再被对象包裹,直接在root节点
{
"list": [1, 2, 3, 4, 5],
"name": "李华"
}
如果没有以上的代码的话,你的请求参数本应该是这样的,返回参数也是如此,并且你需要手动调用方法来处理list中的数据,现在我们只需要在mydata.class对应继承的类中,重写setList方法来对入参进行调整就可以达到效果了
{
"list": {
"list" : [1, 2, 3, 4, 5]
},
"name": "李华"
}