Jackson,实现Bean和JSON之间的灵活转换(SpringMVC默认的JSON转换器)

Jackson介绍

Jackson是Java最受欢迎的JSON类库之一,包含两个不同的解析器:

  1. Jackson ObjectMapper,将JSON转化为Java对象,或者转换为Jackson特定的树结构
  2. Jackson JsonParser,JSON流解析器,每次只解析一个JSON标记(不做讲解)

Jackson还包含两个不同的生成器:

  1. Jackson ObjectMapper,可以从Java对象生成JSON,或者是从Jackson的树结构生成JSON
  2. Jackson Generator,每次生成一个JSON标记(不做讲解)

在springMVC中的具体应用

在spring项目中如何实现自定义类型的转换,例如如何将数字类型的属性转换为特定的枚举类型。一般来说,项目都会使用不同的数字来代表属性的不同含义,如果在代码中直接用数字类型表示可读性比较差,因此都会定义一个枚举来表示。但是如果每次都需要手工将数字转换为枚举那就太麻烦了,而且估计没人喜欢这样做。那解决方法是什么呢?

那就是让Jackson来替我们完成这个工作。来看下如何做,有如下代码:

@RestController
@RequestMapping("/json/exam")
public class ExamController {@PostMapping("/getExamList")public Result<List<GetExamListResVo>> getExamList(@Validated @RequestBody GetExamListReqVo reqVo,@AuthenticationPrincipal UserDetails userDetails)throws IOException {//......}
}

GetExamListReqVo类:

public class GetExamListReqVo {private ExamTypeEnum examType;// get set......
}

ExamStatusEnum枚举类:

public enum ExamTypeEnum implements EnumBase {UNKNOWN(0, ""),EXAM_INDEPENDENT(1, "独立考试"),EXAM_COURSE_SUITE(2, "关联课程");private final int code;private final String msg;ExamTypeEnum(int code, String msg) {this.code = code;this.msg = msg;}// get......
}/**
* 枚举类的公共接口,所有枚举均实现了此接口
*/
public interface EnumBase {int getCode();String getMsg();static <E extends Enum<?> & EnumBase> E codeOf(Class<E> enumClass, Integer code) {E[] enumConstants = enumClass.getEnumConstants();for (E e : enumConstants) {if (e.getCode() == code) {return e;}}throw new IllegalArgumentException("the code didn't match any enum,code:" + code + ",enum class:" + enumClass.getName());}
}

目标:将入参:{“examType”:1} 正确转换为 GetExamListReqVo 对象

为了完成这个目标,只需要编写三个类:

/*** 实现了EnumBase接口的枚举类对象序列化和反序列化*/
public class EnumBaseModule extends SimpleModule {public EnumBaseModule() {super(PackageVersion.VERSION);// 找到EnumBase接口所在的包下所有实现该接口的枚举类Set<Class> set = ClassUtils.getAllClassesFromPackage(EnumBase.class.getPackage().getName()).stream().filter(clz -> clz.isEnum() && EnumBase.class.isAssignableFrom(clz)).collect(Collectors.toSet());// 动态注册所有实现了EnumBase接口枚举类的序列化器和反序列化器到Jacksonset.forEach(enumClass -> {addDeserializer(enumClass, new EnumBaseDeserializer(enumClass));addSerializer(enumClass, new EnumBaseSerializer());});}
}/*** 用来序列化实现了EnumBase接口的枚举类*/
public class EnumBaseSerializer extends JsonSerializer<EnumBase> {@Overridepublic void serialize(EnumBase value, JsonGenerator gen, SerializerProvider serializers)throws IOException {if (value != null) {gen.writeNumber(value.getCode());} else {gen.writeNull();}}
}/*** 将前端传过来的数字转换为实现了EnumBase接口的枚举类对象*/
public class EnumBaseDeserializer<E extends Enum<?> & EnumBase> extends JsonDeserializer<EnumBase> implements ContextualDeserializer {private Class<E> targetClass;public EnumBaseDeserializer() {}public EnumBaseDeserializer(Class<E> targetClass) {this.targetClass = targetClass;}@Overridepublic E deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {return EnumBase.codeOf(targetClass, p.getIntValue());}@Overridepublic JsonDeserializer<?> createContextual(DeserializationContext ctxt,BeanProperty property) throws JsonMappingException {targetClass = (Class<E>) ctxt.getContextualType().getRawClass();return new EnumBaseDeserializer<>(targetClass);}
}

然后配置一下springMVC:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {for (HttpMessageConverter<?> converter : converters) {if (converter instanceof StringHttpMessageConverter) {((StringHttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8);} else if (converter instanceof MappingJackson2HttpMessageConverter) {MappingJackson2HttpMessageConverter messageConverter = (MappingJackson2HttpMessageConverter) converter;messageConverter.setObjectMapper(objectMapper());}}}@Beanpublic ObjectMapper objectMapper() {ObjectMapper objectMapper = new ObjectMapper();objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);// 注册所有实现了EnumBase接口的枚举类处理器objectMapper.registerModule(new EnumBaseModule());return objectMapper;}}

ObjectMapper解析JSON的原理

默认情况下,Jackson通过Java bean的get,set方法,通过去掉get,set再把首字母小写得到的名字去和JSON的属性进行匹配。例如对于getBrand()和setBrand()经过处理得到brand,就会匹配到JSON的brand属性,从而把JSON brand属性的值赋给bean的brand字段。通过一系列这样的处理,就将JSON转换成了Java bean。如果需要以不同的方式来匹配,那么就得使用定制的serializer和deserializer,或者使用Jackson提供的众多的注解。

ObjectMapper创建Java对象的多种方式

Car类定义:

public class Car {private String brand = null;private Integer doors = 0;// get set......
}

测试代码:

        String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";// 从字符串创建Car car = objectMapper.readValue(carJson, Car.class);System.out.println(objectMapper.writeValueAsString(car));// 从Reader创建Reader reader = new StringReader(carJson);car = objectMapper.readValue(reader, Car.class);System.out.println(objectMapper.writeValueAsString(car));File file = ResourceUtils.getFile("classpath:car.json");// 从文件创建car = objectMapper.readValue(file, Car.class);System.out.println(objectMapper.writeValueAsString(car));URL url = ResourceUtils.getFile("classpath:car.json").toURI().toURL();// 从URL创建car = objectMapper.readValue(url, Car.class);System.out.println(objectMapper.writeValueAsString(car));InputStream input = new FileInputStream(file);// 从InputStream创建car = objectMapper.readValue(input, Car.class);System.out.println(objectMapper.writeValueAsString(car));String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";// 解析为数组Car[] cars = objectMapper.readValue(jsonArray, Car[].class);System.out.println(objectMapper.writeValueAsString(cars));// 解析为listList<Car> carList = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>() {});System.out.println(objectMapper.writeValueAsString(carList));String jsonObjectStr = "{\"brand\":\"ford\", \"doors\":5}";// 解析为MapMap<String, Object> map = objectMapper.readValue(jsonObjectStr,new TypeReference<Map<String, Object>>() {});System.out.println(objectMapper.writeValueAsString(map));

配置ObjectMapper的工作方式

有时JSON会拥有比Java对象更多的属性,这种情况下Jackson默认会抛出异常,大概意思是说JSON某个属性未知因为在Java bean中未找到该属性。

然而,有时我们的确会遇到JSON属性比Java对象多的情况。例如我们从REST service获取的JSON会包含更多不需要的属性,这种情况下,Jackson允许通过配置来忽略未知的属性,像这样:

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

原始类型的null处理

public class Car {private String brand = null;private int doors = 0;// 原始类型int// get set......
}

对于{ “brand”:“Toyota”, “doors”:null }

Car类的doors是原始类型int,不能被赋值为null,因此Jackson对于原始类型的null值默认会忽略,然而我们也可以配置Jackson在这种情况下做失败处理:

objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);

设为true后对于试图解析原始类型的null就会抛出异常。还有其他更多的配置等等,例如:

// 遇到无效的子类型也不会解析失败
objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
// 对于空的bean也不会失败
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); 

更多配置请查阅API说明

Jackson对于Date类的处理

默认情况下Date类型属性会被序列化long的毫秒数,然而Jackson也支持将Date序列化成特定格式的日期字符串

public class Transaction {/*** 单独指定序列化后的格式和反序列化时以此格式来解析日期字符串*/@JsonFormat(pattern = "yyyyMMdd HH:mm:ssSSS", locale = "zh_CN", timezone = "GMT+8")private Date date = null;private Date create = null;// get set......
}

测试代码:

        Transaction transaction = new Transaction();transaction.setCreate(new Date());transaction.setDate(new Date());String resJson = objectMapper.writeValueAsString(transaction);// 默认把时间序列化为long// {"date":"20190618 11:33:42845","create":1560828822845}System.out.println(resJson);

可以改为序列化成日期字符串:

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.SIMPLIFIED_CHINESE);dateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));// 设置这个会影响所有Bean的Date序列化和反序列化objectMapper.setDateFormat(dateFormat);resJson = objectMapper.writeValueAsString(transaction);// {"date":"20190618 11:33:42845","create":"2019-06-18 11:33:42"}System.out.println(resJson);String transactionJsonStr = "{\"type\":\"transfer\",\"date\":\"20190118 14:27:52052\",\"create\":\"2019-01-18 14:27:52\"," +"\"transactionTypeEnum\":\"TICKET\",\"transactionType\":2,\"carTypeEnum\":3}";transaction = objectMapper.readValue(transactionJsonStr, Transaction.class);System.out.println(transaction);

Jackson的树模型JsonNode

Jackson内置有树模型用来代表JSON对象,这个树模型具体有什么用呢?当你不知道要解析的JSON的结构你就会发现它会很有用,或者由于某种原因你没法创建一个类来表示这个JSON对象。另外一个好处是你可以在使用这个JSON对象之前操纵这个JSON对象,核心类是JsonNode。

        String carJson ="{ \"brand\" : \"Mercedes\", \"doors\" : 5," +" \"owners\" : [\"John\", \"Jack\", \"Jill\"]," +" \"nestedObject\" : { \"field\" : \"value\" } }";JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);// 或者jsonNode = objectMapper.readTree(carJson);// 取JSON属性值JsonNode brandNode = jsonNode.get("brand");String brand = brandNode.asText();System.out.println("brand = " + brand);JsonNode doorsNode = jsonNode.get("doors");int doors = doorsNode.asInt();System.out.println("doors = " + doors);// 取JSON数组JsonNode jsonArray = jsonNode.get("owners");JsonNode jsonArrayNode = jsonArray.get(0);String john = jsonArrayNode.asText();System.out.println("john = " + john);// 取JSON内嵌对象JsonNode childNode = jsonNode.get("nestedObject");JsonNode childField = childNode.get("field");String field = childField.asText();System.out.println("field = " + field);

JsonNode类是不可变的,意味着我们不能直接创建该类的对象,然而可以使用JsonNode的子类ObjectNode来构建对象:

        // 创建ObjectNodeObjectNode objectNode = objectMapper.createObjectNode();objectNode.put("brand", "Mercedes");objectNode.put("doors", 5);ObjectNode nestNode = objectMapper.createObjectNode();nestNode.put("field", "value");objectNode.set("nestedObject", nestNode);System.out.println(objectMapper.writeValueAsString(objectNode));

Jackson注解

主要可分为三类:

读写注解(同时影响序列化和反序列化过程)

  • @JsonIgnore
  • @JsonIgnoreProperties
  • @JsonIgnoreType
  • @JsonAutoDetect
  • @JsonProperty
  • @JsonTypeInfo
  • @JsonSubTypes

读注解(只影响反序列化过程)

  • @JsonSetter
  • @JsonAnySetter
  • @JsonCreator
  • @JsonDeserialize

写注解(只影响序列化过程)

  • @JsonInclude
  • @JsonGetter
  • @JsonAnyGetter
  • @JsonPropertyOrder
  • @JsonRawValue
  • @JsonValue
  • @JsonSerialize

@JsonIgnore用于需要忽略的属性(不参与序列化和反序列化)

public class PersonIgnore {@JsonIgnoreprivate long personId = 0;private String name = null;// get set......
}PersonIgnore obj = new PersonIgnore(1,"John");
// {"name":"John"}
System.out.println(objectMapper.writeValueAsString(obj));

@JsonIgnoreProperties用于需要忽略的一系列属性

@JsonIgnoreProperties({"firstName", "lastName"})
public class PersonIgnoreProperties {private long personId = 0;private String firstName = null;private String lastName = null;// get set......
}PersonIgnoreProperties personIgnoreProperties = new PersonIgnoreProperties(1,"John","Rod");
// {"personId":1}
System.out.println(objectMapper.writeValueAsString(personIgnoreProperties));; 

@JsonIgnoreType表明所有用到此类的地方都会被忽略

public class PersonIgnoreType {private long personId = 0;private String name = null;private Address address = null;//get set......
}@JsonIgnoreType
public class Address {private String streetName = null;private String houseNumber = null;private String zipCode = null;private String city = null;private String country = null;// get set......
}PersonIgnoreType obj = new PersonIgnoreType(1, "John", new Address("China"));
// {"personId":1,"name":"John"}
System.out.println(objectMapper.writeValueAsString(obj));

@JsonAutoDetect用于检测需要将哪类访问权限的属性参与序列化和反序列化

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
public class PersonAutoDetect {private long personId = 123;private String name = null;// get set......
}

JsonAutoDetect.Visibility用于指明可见性级别,包括ANY, DEFAULT, NON_PRIVATE, NONE, PROTECTED_AND_PRIVATE and PUBLIC_ONLY

@JsonProperty表明序列化和反序列化时以注解指明的为准

public class Person {@JsonProperty("id") private long personId = 0;private String name = null;// get set......
}

JSON:{ “id” : 1234, “name” : “John”}

@JsonTypeInfo和@JsonSubTypes用来处理多态类型的序列化及反序列化,这样说有点抽象,来看下具体例子

抽象父类:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonSubTypes({@JsonSubTypes.Type(value = MemberInformation.class),@JsonSubTypes.Type(value = EcardUserInformation.class)})
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class LoginUserInformation implements Serializable {private static final long serialVersionUID = -933578885036345619L;private String userType = "1";private String ip = "127.0.0.1";// get set......
}

两个具体子类:

public class MemberInformation extends LoginUserInformation implements Serializable {private static final long serialVersionUID = 3334937746962893477L;private String fpcardno = "513712340023";private String passwd = "12346";// get set......
}public class EcardUserInformation extends LoginUserInformation implements Serializable {private static final long serialVersionUID = -8191715041208933113L;private String aid;private String cellPhone;private String email;// get set......
}

测试代码:

        LoginUserInformation loginUserInformation = new EcardUserInformation();((EcardUserInformation) loginUserInformation).setAid("124124124");// {"@class":"org.javamaster.b2c.test.model.jackson.EcardUserInformation","userType":"1","ip":"127.0.0.1",//  "aid":"124124124","cellPhone":null,"email":null}System.out.println(objectMapper.writeValueAsString(loginUserInformation));LoginUserInformation memberInformation = new MemberInformation();((MemberInformation) memberInformation).setPasswd("qq123123");// {"@class":"org.javamaster.b2c.test.model.jackson.MemberInformation","userType":"1","ip":"127.0.0.1",//  "fpcardno":"513712340023","passwd":"qq123123"}System.out.println(objectMapper.writeValueAsString(memberInformation));String jsonStr = "{\"@class\":\"org.javamaster.b2c.core.model.jackson.MemberInformation\",\"userType\":\"1\"," +"\"ip\":\"127.0.0.1\",\"fpcardno\":\"513712340023\",\"passwd\":\"qq123123\"}";memberInformation = objectMapper.readValue(jsonStr, LoginUserInformation.class);System.out.println(objectMapper.writeValueAsString(memberInformation));

@JsonSetter用于表明set方法应该匹配的JSON的属性,当Java bean的属性名和JSON的属性名不一致时就可以使用此注解

public class Person {private long personId = 0;private String name = null;@JsonSetter("id")  // 应该和JSON的id属性匹配public void setPersonId(long personId) { this.personId = personId; }// get set......
}

JSON:{ “id” : 1234, “name” : “John”}

@JsonAnySetter用于指明将所有JSON未知的属性都收集在一起

public class Bag {private Map<String, Object> properties = new HashMap<>();@JsonAnySetterpublic void set(String fieldName, Object value){this.properties.put(fieldName, value);}public Object get(String fieldName){return this.properties.get(fieldName);}
}

所有JSON未知的属性都会收集到Bag类的properties属性里

@JsonCreator用于表明Java bean有一个构造方法能够匹配JSON的属性和bean的属性,对于一些没有set方法的bean(不可变对象)来说这个注解是很有用的。

public class PersonImmutable {private final long id;private final String name;@JsonCreatorpublic PersonImmutable(@JsonProperty("id")long id, @JsonProperty("name")String name) {this.id = id;this.name = name;}// get set......
}

JSON:{ “id” : 1234, “name” : “John”}

@JsonDeserialize用于定制bean属性的反序列化过程

public class PersonDeserialize {private long id = 0;private String name = null;// 这里我们想把1映射为true,0映射为false@JsonDeserialize(using = OptimizedBooleanDeserializer.class)private boolean enabled = false;// get set......
}public class OptimizedBooleanDeserializer extends JsonDeserializer<Boolean> {@Overridepublic Boolean deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {String text = jsonParser.getText();if ("0".equals(text)) {return false;} else {return true;}}
}

JSON:{“id” : 1234, “name” : “John”,“enabled”: 0}

@JsonInclude用于表明值满足特定条件的属性才会被序列化

 // 说明值不为null且不为空字符串的属性才会被序列化
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class PersonInclude {private long personId = 0;private String name = null;private String name1 = "";private String name2 = "John";// get set......
}

JSON:{“personId” : 0, “name2” : “John”}

@JsonGetter用于指明序列化后的属性名而不是用bean的字段名

public class PersonGetter {private long personId = 0;@JsonGetter("id")public long personId() { return this.personId; }@JsonSetter("id")public void personId(long personId) { this.personId = personId; }
}

序列化后: {“id”: 0}

@JsonAnyGetter能够让你使用一个Map作为容器包含任何你想要序列化的属性

public class PersonAnyGetter {private Map<String, Object> properties = new HashMap<>();@JsonAnyGetterpublic Map<String, Object> properties() {return properties;}public Map<String, Object> getProperties() {return properties;}
}

@JsonPropertyOrder用于指明bean属性序列化的顺序

@JsonPropertyOrder({"name", "personId"})
public class PersonPropertyOrder {private long personId = 0;private String name = "John";// get set......
}

序列化后: {“name”:“John”,“personId”,0}

@JsonRawValue用于表明属性值不做任何处理原样输出,String类型的值序列化后会被双引号括住,使用此注解后将不会加上双引号

public class PersonRawValue {private long personId = 0;@JsonRawValueprivate String address = "$#";// get set......
}

不加此注解时输出是这样的:{“personId”:0,“address”:"KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲"},加了后输出是这样的:{"…#},这很明显是非法的JSON结构,所以我们为什么要这么做呢?这么做的理由是address属性的值是JSON字符串来的,像这样:

public class PersonRawValue {private long personId = 0;@JsonRawValueprivate String address = "{ \"street\" : \"Wall Street\", \"no\":1}";// get set......
}

序列化后是这样的:{“personId”:0,“address”:{ “street” : “Wall Street”, “no”:1}}

不加注解时序列化后是这样的:{“personId”:0,“address”:“{ “street” : “Wall Street”, “no”:1}”}

@JsonValue表明Jackson不做序列化,由此注解标注的方法完成序列化工作

public class PersonValue {private long personId = 0;private String name = null;@JsonValuepublic String toJson(){return this.personId + "," + this.name;}
}

序列化后是这样的:“0,null”

@JsonSerialize用于定制bean属性的序列化过程

public class PersonSerializer {private long personId = 0;private String name = "John";// 这里希望把false序列化成0,true序列化成1@JsonSerialize(using = OptimizedBooleanSerializer.class)private boolean enabled = false;// get set......
}public class OptimizedBooleanSerializer extends JsonSerializer<Boolean> {@Overridepublic void serialize(Boolean aBoolean, JsonGenerator jsonGenerator,SerializerProvider serializerProvider)throws IOException {if (aBoolean) {jsonGenerator.writeNumber(1);} else {jsonGenerator.writeNumber(0);}}
}

完全定制类的序列化和反序列化过程

        // 完全定制类的序列化和反序列化过程SimpleModule carModule = new CarModule();// 注册针对这个类型的处理模块objectMapper.registerModule(carModule);Car car = new Car();car.setBrand("BMW");car.setDoors(4);String json = objectMapper.writeValueAsString(car);System.out.println(json);car = objectMapper.readValue(json, Car.class);System.out.println(objectMapper.writeValueAsString(car));

其中CarModule CarSerializer CarDeserializer的定义:

// 类型处理模块
public class CarModule extends SimpleModule {public CarModule() {super(PackageVersion.VERSION);addDeserializer(Car.class, new CarDeserializer(Car.class));addSerializer(Car.class, new CarSerializer(Car.class));}
}// 序列化器
public class CarSerializer extends StdSerializer<Car> {private static final long serialVersionUID = 2807109332342106505L;public CarSerializer(Class<Car> c) {super(c);}@Overridepublic void serialize(Car car, JsonGenerator jsonGenerator,SerializerProvider serializerProvider)throws IOException {jsonGenerator.writeStartObject();if (car.getBrand() != null) {jsonGenerator.writeStringField("brand", car.getBrand());} else {jsonGenerator.writeNullField("brand");}if (car.getDoors() != null) {jsonGenerator.writeNumberField("doors", car.getDoors());} else {jsonGenerator.writeNullField("doors");}jsonGenerator.writeEndObject();}
}// 反序列化器
public class CarDeserializer extends StdDeserializer<Car> {private static final long serialVersionUID = 4977601024588834191L;public CarDeserializer(Class<?> c) {super(c);}@Overridepublic Car deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException {Car car = new Car();while (!parser.isClosed()) {JsonToken jsonToken = parser.nextToken();if (JsonToken.FIELD_NAME == jsonToken) {String fieldName = parser.getCurrentName();parser.nextToken();if ("doors".equals(fieldName)) {car.setDoors(parser.getValueAsInt());} else if ("brand".equals(fieldName)) {car.setBrand(parser.getValueAsString());}}}return car;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis之工作原理,简单实体的增加、修改、删除、查询_Mybatis-原理总结

一、MyBatis之工作原理 MyBatis是一个半自动映射框架。所谓半自动&#xff0c;是相对Hibernate全表映射而言的&#xff0c;MyBatis需要手动匹配提供POJO、SQL和映射关系。 我们知道&#xff0c;JDBC有四个核心对象&#xff1a; &#xff08;1&#xff09;DriverManager&#…

MySQL优化:如何避免回表查询?_什么是索引覆盖?

数据库表结构&#xff1a; create table user (id int primary key,name varchar(20),sex varchar(5),index(name) )engineinnodb;select id,name where nameshenjianselect id,name,sex where nameshenjian多查询了一个属性&#xff0c;为何检索过程完全不同&#xff1f; 什…

mysql提示Column count doesn‘t match value count at row 1错误

我们在对数据库进行添加信息时可能会遇到如下错误&#xff1a; Column count doesn’t match value count at row 1 该错误的意思是传入表的字段数和values值的个数不一样 我总结了一下&#xff0c;主要有3个易错点&#xff1a; 1.要传入表中的字段数和values后面的值的个数不…

java 阅发布模式_redis发布订阅模式

一 前言虽然有消息队列&#xff0c;我们还是要了解一下redis发布订阅模式哟&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;二发布订阅模式PUBLISH 命令向通道发送信息&#xff0c;此客户端称为publisher 发布者&#xff1b;SUBSCRIBE 向命令通道订阅信息&#…

把实体 转为json 数据格式---jackson 的详细用法_Jackson快速入门

首先介绍三个注解&#xff1a; JsonAutoDetect (method/field):作用于方法或字段&#xff0c;用来表明&#xff0c;当生成json的时候忽略有该annotation的方法或字段 JsonIgnore 过滤不需要转成json的属性 JsonIgnoreProperties 主要用于过滤掉一些不需要的属性 以上三个注…

python 猴子补丁_python面试题精讲——monkey patch(猴子补丁)

前言本次依然是选自python面试题系列&#xff0c;将一个比较偏的概念&#xff0c;可能很多人没怎么听说过——猴子补丁&#xff0c;其实所讲的内容很简单&#xff0c;它得益于python灵活的语法、一切皆对象的思想&#xff0c;一起来看看看看吧&#xff01;目录一、什么是monkey…

java 类的加载顺序_Java 中类的加载顺序

这其实是去年校招时我遇到的一道阿里巴巴的笔试题(承认有点久远了-。-)&#xff0c;嗯&#xff0c;如果我没记错的话&#xff0c;当时是作为Java方向的一道选做大题。当然题意没有这么直白&#xff0c;题目只要求你写出程序运行后所有System.out.println的输出结果&#xff0c;…

Jackson转换json大写_关于jackson转化json的原理_jackson序列化和反序列化Json

背景 web工程中&#xff0c;数据交互是不可避免的&#xff0c;相比xml&#xff0c;json是现在流行的数据交互。 在调试接口中&#xff0c;发现返回字段的大小写不是我所期望的&#xff0c;原本应该返回的nNum字段变成了nnum&#xff0c;这样就导致和前端约定的有出入了。 ja…

groovy+mysql数据库_使用Groovy连接到MySQL

我正在尝试使用MAC OS 10.10.5 Yosemite上的以下Groovy代码连接到MySQL数据库import groovy.sql.Sqltry{def dbURL jdbc:mysql://localhost:3306/sakiladef dbUserName rootdef dbPassword Orange27def dbDriver com.mysql.jdbc.Driverlog.info(Good)def db Sql.newInstan…

svn利用TortoiseSVN忽略文件或文件夹(目录)

忽略已经版本控制的文件 如果你不小心添加了一些应该被忽略的文件&#xff0c;你如何将它们从版本控制中去除而不会丢失它们&#xff1f;或许你有自己的IDE配置文件&#xff0c;不是项目的一部分&#xff0c;但将会花费很多时间使之按照自己的方式工作。 如果你还没有提交&am…

java打印两个小人_[原创]Java画小人与阶梯问题的解答

package test;/**#Python源代码:#By:Cat73 QQ 1901803382#2014年7月22日19:33:12#画图函数 width:台阶的宽度(至少为4) hight:台阶的高度(至少为4) count:台阶的数量(至少为3)def paint(width, hight, count):for i in range(1, count):other(width, hight, count, i)#画出最后…

SpringMVC 参数绑定详解

概述 记得之前跟前端同事联调接口的时候&#xff0c;后端SpringMVC需要接收数组类型的参数&#xff0c;然后跟前端说需要传数组类型过来。后来前端童鞋传了数组&#xff0c;但是后端接收不成功&#xff0c;联调失败。那时候由于时间关系没有仔细研究这块&#xff0c;当时想了个…

java httpcomponents_java – 如何使用Apache httpcomponents从NHttpRequ...

我正在使用Apache httpcomponents实现一个彗星式(延迟响应)http服务器.我的代码与http://hc.apache.org/httpcomponents-core-ga/examples.html的“基本非阻塞HTTP服务器”示例非常相似我使用DefaultServerIOEventDispatch和DefaultListeningIOReactor来分派请求,就像在示例代码…

java servlet是单例吗_关于java:为什么apache servlet是单例?

本问题已经有最佳答案&#xff0c;请猛点这里访问。HttpServletRequest request;HttpServletResponse response;public void doGet(HttpServletRequest request , HttpServlet response){this.request request;this.response response;}如果此servlet一次收到多个请求会发生什…

OkHttp的作用_为什么要使用OkHttp?(笔记)

OkHttp的作用 OkHttp is an HTTP client。 如果是HTTP的方式想得到数据&#xff0c;就需要我们在页面上输入网址&#xff0c;如果网址没有问题&#xff0c;就有可能返回对应的String字符串&#xff0c;如果这个地址是返回字符串的话。 OkHttp是在idea代码中&#xff0c;通过调…

java 连接远程服务器_java实现连接远程服务器并执行命令的基本原理

一、所需jar包需要借助Ganymed SSH的jar包: ganymed-ssh2-build210.jar二、实现原理Ganymed SSH-2 java在整个访问过程中担当SSH的客户端&#xff0c;由于Linux系统自带SSH服务&#xff0c;所以可以直接访问Linux系统并执行相关命令&#xff0c;而 Windows系统则需要首先安装S…

SpringMVC接收基本类型和包装类型

先看一个示例&#xff1a; 注意这两个参数都没有加RequestParam注解。 测试&#xff1a; 直接报错。即没有加RequestParam注解&#xff0c;基本数据类型参数是必填的。 再测试&#xff1a; 直接返回null&#xff0c;也就是说包装类型参数&#xff0c;没有加RequestParam注解&…

SpringMVC 【参数绑定详讲、默认支持参数类型、自定义参数绑定、RequestParam 注解】

SpringMVC 第四篇【参数绑定详讲、默认支持参数类型、自定义参数绑定、RequestParam 注解】 参数绑定 我们在 Controller 使用方法参数接收值&#xff0c;就是把 web 端的值给接收到 Controller 中处理&#xff0c;这个过程就叫做参数绑定… 默认支持的参数类型 从上面的用…

MySQL保留字不能作为字段名使用_Table字段不能设为关键字range,range在mysql中是分区,是mysql的关键字

mysql 中Table字段不能设为关键字range&#xff0c;range在mysql中是分区,是mysql的关键字 在设计MySQL字段的时候&#xff0c;无意中使用InOut这个名称作为字段名称&#xff0c;结果前端提交后就是没有写入数据库&#xff01;但后端没有任何提示&#xff0c;跟踪mySQL日志&…

java+的数组分割符_Java:使用分隔符连接基元数组

小编典典这是我想出的。有几种方法可以执行此操作&#xff0c;它们取决于您使用的工具。使用StringUtils和ArrayUtils来自CommonLang&#xff1a;int[] arr new int[] {1, 2, 3, 4, 5, 6, 7};String result StringUtils.join(ArrayUtils.toObject(arr), " - ");您不…