使用MyBatis返回map对象,字段值为null时不返回或返回null,目标返回自定义的默认值...
在项目开发中,为了减少json传输的数据量,加快响应速度,通常当字段值为null时,我们不会把字段返回给前端。但在实际开发中可能像Android 与iOS 更希望我们可以返回完整的数据,
在mybatis 中,返回map字段值为null 时是有返回的,例如:
column="name" property="name" jdbcType="VARCHAR" javaType="java.lang.String"/>
在mapper.xml 文件中使用以上的格式返回名称为name的数据,如果name的值为null ,那么返回值也为null,并不会无故的消失掉,所以我们如果需要字段值为null的字段不回传,需要用到另外的jar 包
我当前项目中使用的jar 为:
com.fasterxml.jackson.core
jackson-core
2.9.2
com.fasterxml.jackson.core
jackson-databind
2.9.2
com.fasterxml.jackson.core
jackson-annotations
2.9.2
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
2.9.2
org.springframework
spring-web
5.0.2.RELEASE
以下贴上json 代码
1 package module.spring; 2 3 import com.fasterxml.jackson.annotation.JsonInclude; 4 import com.fasterxml.jackson.core.JsonGenerator; 5 import com.fasterxml.jackson.databind.JsonSerializer; 6 import com.fasterxml.jackson.databind.ObjectMapper; 7 import com.fasterxml.jackson.databind.SerializationFeature; 8 import com.fasterxml.jackson.databind.SerializerProvider; 9 import com.fasterxml.jackson.databind.introspect.Annotated; 10 import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; 11 import com.fasterxml.jackson.databind.module.SimpleModule; 12 import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; 13 import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; 14 import message.Message; 15 import org.apache.commons.lang3.ClassUtils; 16 import org.springframework.http.HttpOutputMessage; 17 import org.springframework.http.converter.HttpMessageNotWritableException; 18 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 19 20 import java.io.IOException; 21 import java.lang.reflect.Type; 22 import java.util.*; 23 24 public class JSON extends MappingJackson2HttpMessageConverter { 25 26 private static final ThreadLocal
上面被我注释的代码并不是错误,我注释它只因为我根本用不到它,跟我的需求不符:
我是为了给返回值设定默认值,刚开始我的思路为如果返回的字段类型为String 类型并且返回值为null,则返回 “” ,返回的字段类型为Integer 类型并且返回值为null,则返回 0 ,""和 0 是我自定义的可以随意的更改。。
但是我发现返回值为null时 字段没有类型,对是没有类型 就是null,我只能对null进行处理。
JsonSerializer
不过也不是全无收获,起码如果我想要对返回值中的一些字段的值进行过滤的话可能比较方便...
既然这儿不行我只能往更上游,可以拿到返回的字段的类型的地方实现我返回自定义默认值的目标。
我找到了mybatis 的 BaseTypeHandler 在这儿对mybatis 从数据库取出来的字段进行设置默认值。BaseTypeHandler 有很多的子类,分别处理不同的返回类型。例如:DateTypeHandler、StringTypeHandler ..
所有的数据类型都有它的子类的实现。 我直接继承了类DateTypeHandler,把默认返回null 改为 默认返回 new Date(0), 发现好使??????注意这里我并没有更改配置,也没有在mapper.xml 中使用 typeHandler="" 这个属性引用我写好的子类
package dao.typehandler.myTypeHander; import exception.SimpleException; import org.apache.ibatis.executor.result.ResultMapException; import org.apache.ibatis.type.DateTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import java.sql.*; import java.util.Date; /** * @author tianyuting * @date 2019/11/110:59 */ //@MappedJdbcTypes({JdbcType.DATE,JdbcType.TIMESTAMP}) 这个注解在一开始是没有加的。如果不加需要在mapper.xml中使用typeHandler="" 进行引用
public class MyDateTypeHandler extends DateTypeHandler { @Override public Date getResult(ResultSet rs, String columnName) throws SQLException { Date result; try { result = getNullableResult(rs, columnName); } catch (Exception e) { throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e); } return result; } @Override public Date getNullableResult(ResultSet rs, String columnName) throws SQLException { Timestamp sqlTimestamp = rs.getTimestamp(columnName); if (sqlTimestamp != null) { // throw new SimpleException("fffff"); return new Date(sqlTimestamp.getTime()); } return new Date(0); } @Override public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException { Timestamp sqlTimestamp = rs.getTimestamp(columnIndex); if (sqlTimestamp != null) { return new Date(sqlTimestamp.getTime()); } return new Date(0); } @Override public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { Timestamp sqlTimestamp = cs.getTimestamp(columnIndex); if (sqlTimestamp != null) { return new Date(sqlTimestamp.getTime()); } return new Date(0); } }
想着既然这样可行 那就把String 也弄个默认为“” 的子类。好嘛..不行,String死活不行,必须得使用 typeHandler="" 在mapper.xml 中进行引用。可我就想不明白了,为什么其中一个可以一个就不行呢?如果有知道的大佬,还请您不吝指点一番...在下感激不尽
按我的理解Java的继承 与多态 在这儿完全不够用,代码jar 已经写好了我现在的子类实现就是一个没人调用的存在,多态的父类引用指向子类对象在我这里完全的被违背。感觉哪儿出了问题,是不是我的眼界太窄,或许人家使用了反射什么的???
如果有大佬有思路实现一个只通过继承就可以覆盖父类的方法执行子类方法,如果没有子类就执行父类方法的程序,可不可以分享一下 ...我是完全没有思路啊。只能说自己辣鸡一个。
1 package dao.typehandler.myTypeHander; 2 3 import org.apache.ibatis.executor.result.ResultMapException; 4 import org.apache.ibatis.type.JdbcType; 5 import org.apache.ibatis.type.MappedJdbcTypes; 6 import org.apache.ibatis.type.StringTypeHandler; 7 8 import java.sql.*; 9 10 /** 11 * 12 */ 13 //@MappedJdbcTypes(JdbcType.VARCHAR) 这个注解在一开始是没有加的。如果不加需要在mapper.xml中使用typeHandler="" 进行引用 14 public class MyStringTypeHandler extends StringTypeHandler { 15 16 @Override 17 public String getResult(ResultSet rs, String columnName) throws SQLException { 18 String result; 19 try { 20 result = getNullableResult(rs, columnName); 21 } catch (Exception e) { 22 throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e); 23 } 24 return result; 25 26 } 27 @Override 28 public String getNullableResult(ResultSet rs, String columnName) 29 throws SQLException { 30 String rsString = rs.getString(columnName); 31 if(rsString==null){ 32 return ""; 33 } 34 return rsString; 35 } 36 37 @Override 38 public String getNullableResult(ResultSet rs, int columnIndex) 39 throws SQLException { 40 String rsString = rs.getString(columnIndex); 41 if(rsString==null){ 42 return ""; 43 } 44 return rsString; 45 } 46 47 @Override 48 public String getNullableResult(CallableStatement cs, int columnIndex) 49 throws SQLException { 50 String rsString = cs.getString(columnIndex); 51 if(rsString==null){ 52 return ""; 53 } 54 return rsString; 55 } 56 }
我感觉在mapper.xml中使用 typeHandler="" 是有一点太麻烦了,每一个我都要加一个typeHandler="",还要把字段一一的都写到 resultMap 中去,实在是感觉不咋地.
所以我继续上网搜索 typeHandler 这个东西,顺便说一句,看官方文档,啥都有,有不了解的直接找官方文档是最好的。想走捷径,除非这个东西到处都是,分分钟就已经解决..分分钟不了就去看官方吧.贴个链接mybatis官方文档(中文)
好了,需要把配置也该一改,
<?xml version="1.0" encoding="UTF-8"?>
configuration PUBLIC "-//mybatis.org//DTD SQL Map Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
name="logImpl" value="LOG4J2"/>
name="useGeneratedKeys" value="true"/>
name="defaultExecutorType" value="REUSE"/>
name="lazyLoadingEnabled" value="true"/>
name="aggressiveLazyLoading" value="false"/>
name="mapUnderscoreToCamelCase" value="true"/>
name="cacheEnabled" value="true"/>
name="callSettersOnNulls" value="true"/>
javaType="java.lang.String" handler="dao.typehandler.myTypeHander.MyStringTypeHandler"/>
javaType="java.util.Date" handler="dao.typehandler.myTypeHander.MyDateTypeHandler"/>
interceptor="com.github.pagehelper.PageInterceptor">
name="helperDialect" value="mysql"/>
name="reasonable" value="true"/>
改完不好使,还得再类上加注解 @MappedJdbcTypes ,好了这个东西可以自定义默认值了。。。 除了业务代码,难一点的东西就很吃力,现在工作都快2年了,源码看的迷迷糊糊的。难过....你们有过这样的感觉吗?