精华内容
下载资源
问答
  • 那么这次返回传值的表现是什么呢,那就是在返回后,arr 数组实际上持续存在,并且因为 arr 实际上是一个函数外定义的变量,因此在函数内部传值返回的时候,不可以使用 C++11 新增的自动右值转化变成移动语义以避免...

    一、引言

    停滞了很久,最近又开始细细品味起《Data Structure And Algorithm Analysis In C++》这本书了。这本书的第一章即为非常好的 C++11 统领介绍的教材范文,可能对于 C++11 新手来说,作者这样短篇幅的介绍或许有些苍白晦涩,但是对于我这种有一定 C++ 开发经验并且有研读过 《C++ Primer 5th》的人来说,作者这几页简直就是让我对 C++11 的整体脉络有了更加宏观的认识。

    话不多说,在之前,我看了这本书的第 1.5.3 节后,总结了一篇博客:
    细谈 C++ 传参的四种方式:按值传参、按左值引用传参、按常量引用传参以及按右值引用传参

    可以说,我这篇博客里面那种画出来的图(什么时候选择使用哪种传参方式)就是非常精炼的总结。

    C++ 除了四种传参方式,其实还有三种返回传值的方式。C++ 的代码为什么这么难以理解,从入参到出参,这都是有一些门门道道的。

    同样的,这里,我拿出这本书的第 37 页的一块函数模板的代码,你能解释出来为什么这个 findMax 函数要使用按常量引用的方式返回传值吗:

    /**
     * Return the maximum item in array a.
     * Assumes a.size() > 0.
     * Comparable objects must provide operator< and operator=
     */
     template <typename Comparable>
     const Comparable & findMax(const vector<Comparable> & a)
     {
     	int maxIndex = 0;
    	for(int i = 0; i < a.size(); ++i)
    		if (a[maxIndex] < a[i])
    			maxIndex = i;
    	return a[maxIndex];
     }
    

    这里以这段代码开篇引言,后面会仔细介绍 C++ 的三种返回传值的方式,以及总结一下什么时候,我们该选择使用哪种返回传值的方式。

    ps: 本篇博客大量参考了《Data Structure And Algorithm Analysis In C++》书中的解释和代码。

    二、一点碎碎念的讨论

    让我们忘掉那么多复杂的概念,我们一起来仔细思考一下,C++ 返回传值的表现:被传递的值是否持续存在、传递过程中是否发生了拷贝、传递过程中是否会自动转化成移动语义(C++11 新增)等等。这些表现到底与哪些因素有关呢?

    通过仔细研读《Data Structure And Algorithm Analysis In C++》书中的阐述,我认为 C++ 返回传值的表现的不同,主要与两方面有关系:

    1. 被返回的值

    函数体内,被返回的值,它是左值还是右值,是临时变量(函数体内定义的)还是非临时变量(函数体外定义的),都会影响到返回传值的表现。

    这里,我简单举个例子:

    LargeType randomItem1 (const vector<LargeType> & arr)
    {
        return arr[randomInt(0, arr.size() - 1)];
    }
    vector<LargeType> vec;
    // copy
    LargeType item1 = randomItem1(vec);
    

    这里,vec 以按常量引用的方式传入 randomItem1 函数,它是一个非临时变量,并且是一个左值返回。那么这次返回传值的表现是什么呢,那就是在返回后,arr 数组实际上持续存在,并且因为 arr 实际上是一个函数外定义的变量,因此在函数内部传值返回的时候,不可以使用 C++11 新增的自动右值转化变成移动语义以避免复制拷贝开销。

    这是什么意思呢,我们再来看一段代码就好了:

    vector<int> partialSum(const vector<int> & arr)
    {
    	vector<int> result(arr.size());
    	result[0] = arr[0];
    	for (int i = 1; i < arr.size(); ++i)
    		result[i]  = result[i - 1] + arr[i];
    	return result;
    }
    vector<int> vec;
    // copy in old C++, move in C++11
    vector<int> sums = parialSum(vec); 
    

    这段代码乍一看,仿佛并没有什么不同,也是普通返回类型,也是按常量引用传值。可是这个调用的返回传值的表现就大大不同了,传统 C++ 确实还是会按值返回,发生拷贝,但是 C++11 中就会自动转化为移动语义,使用移动替换拷贝节省开销。

    为什么呢?这就是因为返回的 result 实际上是一个临时变量,同右值在这里有异曲同工之妙的地方在于,他们在离开了函数之后都会自动的消失,也就是说,我们将其值移动到返回接受这个值的地方完全没有问题,并且还能节省资源开销,何乐而不为呢?而 C++11 确实也是这么做的。

    总而言之,返回传值的表现,与被返回的值有关系。其是临时变量或者右值,就有拷贝转移动的可能(返回类型要是普通类型),其是非临时变量,则有返回后持续存在的特性。

    2. 返回类型

    函数定义的返回类型会影响返回传值的表现,这个也不难理解。

    一般来说,返回类型如果定义为:

    1. 按值返回,则要产生拷贝;

    2. 按常量引用返回,则如果调用方使用常量引用接受返回值则不产生拷贝

    3. 按引用返回,则既不产生拷贝,并且还能对其值进行修改(这种情况虽然少见,但是也有存在)。

    这里,我在介绍 C++ 的三种返回传值之前先进行了一些讨论,希望能够对这三种返回传值类型有一些初步的了解。

    接下来,我们来结合着例子来详细的探讨下这三种返回传值的方式。

    三、这个标题才是正餐

    有了前面的一些准备知识,我们来细细的探讨下 C++ 返回传值的三种方式。

    1. 按值返回

    按值返回,可能是初学者最熟悉的返回方式了。

    LargeType randomItem1 (const vector<LargeType> & arr)
    {
        return arr[randomInt(0, arr.size() - 1)];
    }
    vector<LargeType> vec;
    LargeType item1 = randomItem1 (vec);
    

    我拿出来了同样的例子,我们声明了 randomItem1 的返回类型为 largeType,并未加上 & 或者 const 这就是简单的按值返回。我们将 vec 这个 vector 数组按常量引用传入 randomItem1 函数中去,目的是让 vec 在函数内不至于被改变,并且还能避免传参拷贝带来的资源消耗。

    在带出参数的时候,我们发现,带出来的 arr[randomInt(), arr.size() - 1] 其实上是一个非临时变量的左值,在返回传值的时候,需要拷贝给接受该值的 item1 变量。

    说的很复杂,其实很简单,那就是这里发生了拷贝开销。

    前面也有提到过,在 C++11 一些情况下,拷贝可能会被自动转化为移动。那么这里可以吗?

    答案是不行的。

    能被转化为移动语义的,一般都带有临时的语义,要么是被返回的值是临时变量,要么就是一个临时的右值,否则不能转化为移动语义。

    总的来说,那就是按值返回一般带有拷贝的意味,只是 C++11 会进行一些优化,会将临时的值的返回自动转化为移动来节省拷贝开销。

    2. 按常量引用返回

    既然按值返回会出现拷贝的开销,那么为了解决这个问题,加上一个引用不就好了吗。因此,按(常量)引用返回的方式就应运而生。

    顾名思义,常量,意味着不能对返回值进行修改,引用,则意味着避免拷贝开销。

    const LargeType & randomItem2(const vector<LargeType> & arr)
    {
        return arr[randomInt(0, arr.size() - 1)];
    }
    vector<LargeType> vec;
    // copy
    LargeType item1 = randomItem2(vec);
    // no copy
    const LargeType & item2 = randomItem2(vec);
    

    这里值得注意的是,按常量引用返回的调用,需要同样以常量引用去接受它,否则常量引用向引用类型的转换(const 转非 const)是需要拷贝转换的。

    另外,可能你已经注意到了,那么按引用返回传值呢?不就可以对返回值进行修改了吗?

    确实是这样,但是这种返回传值的方式比较少见,多见的还是常量引用传值。

    3. 按引用返回

    按引用返回的使用场景确实比较少,多见于调用者需要对于返回对象的内部的数据进行修改。

    template <typename Object>
    class martix
    {
    public:
    	matrix(vector<vector<Object>> v) : array{v}
    		{}
    	const vector<Object> & operator[](int row) const
    		{ return array[row]; }
    	vector<Object> & operator[](int row)
    		{ return array[row]; }
    private:
    	vector<vector<Object>> array;
    };
    

    上述代码中,定义了一个二维数组 matrix 类,其元素类型为 Object。同时定义了按常量引用返回的 operator= 操作符和按常量引用返回的 operator= 操作符。这样是为了方便取值的只读语义和修改值的修改语义(accessor or mutator)。

    正因为我们这么定义了,所以我们就可以写出下列的代码:

    void copy(const matrix<int> & from, matrix<int> & to)
    {
    	for (int i = 0, i < to.numrows(); ++i)
    		to[i] = from[i];
    }
    

    乍一看这个函数的定义非常好,from 是被拷贝的值以按常量引用传入,to 是需要修改的值以引用传入。为了使得这个 to[i] = from[i] 等式编译通过,我们必须定义两个版本的 operator= 操作符。

    左侧的 to[i] 就是按引用返回的 operator 操作符,右侧的 from[i] 则是按照常量引用返回的 operator 操作符。

    这样达到了语义上的统一。

    四、实际开发中如何选择

    那么详细探讨了这三种返回传值的方式,我们在开发中该如何选择呢?

    这里我还是画了一个图来阐述:

    1

    注:或许会有人问,按值返回有没有常量的概念,答案是当然没有。因为按值返回返回的是值的拷贝,你加个常量概念也无法达到对原值的 const 约束。也就是说,按值返回绝对是没有 const 修饰的,因为毫无意义:)

    五、总结

    C++ 的代码很难看懂,也许就在这些方面,一方面入参的四种方式,一方面出值的三种方式。相互组合,就会让人觉得晦涩难懂。

    其实好好深入到里面弄清楚其里面的含义,也就比较好理解了。

    这篇和上一篇写传参四种方式的博客写的非常认真,也希望能够对 C++ 初学者能有一些帮助 _

    To be Stronger:)

    展开全文
  • Mybatis返回单个实体或者返回List

    万次阅读 多人点赞 2018-04-13 14:49:50
    1.返回某个实体 &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;select id=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;identification&amp;amp;amp;amp;amp;amp;amp;amp;amp...

    Mybatis 的强大之处之一体现在映射语句上,让我们可以使用简单的配置,就可以实现对参数和返回结果的映射。

    实体

    // com.test
    @Data
    public class User{
    	private String userId;
    	private String userName;
    	private String userPassword;
    	private Date createTime;
    }
    

    DAO

    public interface UserMapper{
    	User getUserById(String userId);  //返回单个实体
    	List<User> getUserByName(String userName); //返回List
    	Map<String,Object> getUserInfoById(String userId);
    	List<Map<String,Object>> getUserInfoByName(String userName);
    }
    

    数据库

    create table user{
    	USER_ID varchar(40),
    	USER_NAME varchar(200),
    	USER_PASSWORD varchar(100),
    	CREATE_TIME datetime,
    	....
    }
    

    1.返回某个实体

    mybatis映射文件

    	<select id="getUserById" parameterType="string" resultType="com.test.User">
    		select * from user where id = #{userId}
    	</select>
    
    • id :identification:语句的标识,在同一个mapper映射文件下id需要唯一
    • parameterType: 参数类型,可以不写。因为 MyBatis 可以推断出传入语句的具体参数
    • resultType: 全限定类名或者是类型别名.

    当使用resultType来映射结果时,需要 数据库表的列名或列别名 和 类的属性名相同,这样才能进行字段的匹配(USER_ID 和userId 就不能匹配)。但是如果在Mybatis配置文件中设置了

    <settings>
      <setting name="mapUnderscoreToCamelCase" value="true"/> <!--开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。-->
    </settings>
    

    此时,表列名的下划线标记方式可以映射到驼峰标记的形式。(USER_ID -> userId)。mybatis进行映射时会将实体类属性和数据库列名(别名)都转化为大写来比较,所以USER_ID 和 UserId,userID等都可以匹配。

    TooManyResultsException

    返回单个实体时,调用方法 getUserById,但是如果是因为数据错误导致实际查询结果存在多个时,则会抛出异常。

    User getUserById(String userId);  //返回单个实体
    

    当实际返回值有多个时则抛出异常。

    org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 2
    

    除非可以确定最多只能查询到一条结果,否则的话不建议这么写.可以尝试返回集合的方式。

    2.返回List<entityName>

    	<select id="getUserByName"  resultType="com.test.User">
    		select * from user where user_name = #{userName}
    	</select>
    

    返回List<T> 集合时,resultType设置为集合元素的类型即T。然后使用返回几何数据的Mapper方法即可。

    List<User> getUserByName(String userName); //返回List
    

    从上面可以看到,返回单个实体与返回集合的resultType指定类型是一样的,不一样的地方在Mapper接口或者sqlSession中定义的返回结果类型。实际上mybatis执行查询的时候也都是使用sqlSession.selectList()来进行查询的。

    1. 使用Mapper 接口的方式的查询结果时,Mybatis会生成该接口的代理类(MapperProxy),然后根据Method的getReturnType()方法,拿到返回类型,来确定返回的是列表还是单个实体。最后也是调用sqlSession的一些方法。
    2. 使用SqlSession时,提供了selectOne() 或者selectList()来返回单个实体或者集合。selectOne 实际会调用selectList获取结果。

    推荐使用返回List的方式来查询结果

    //查询单条结果
    List<User> userList= mapper.getUserByName(userName);
    if(userList.isEmpty() || userList.size() >1)//期望获得一条结果
    	//业务处理,一般是抛出异常或者直接返回错误结果
    	//return xx;	
    	//throw xxx
    User user = userList.get(0);
    
    扩展

    为什么查询单条和查询多条使用的是相同的resultType,而返回的结果不同呢。
    这是因为Mybatis 在内部进行数据查询的时,无论查询单条还是多条都是通过selectList实现的,不同的是查询单条Mybatis会获取第一条,并且如果结果中存在多条时抛出异常 TooManyResultsException

    • 查询单数据

        @Override
        public <T> T selectOne(String statement, Object parameter) {
          // Popular vote was to return null on 0 results and throw exception on too many.
          List<T> list = this.<T>selectList(statement, parameter);
          if (list.size() == 1) {
            return list.get(0);
          } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
          } else {
            return null;
          }
        }
      
    • 查询列表

        private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
          List<E> result;
          Object param = method.convertArgsToSqlCommandParam(args);
          if (method.hasRowBounds()) {
            RowBounds rowBounds = method.extractRowBounds(args);
            result = sqlSession.<E>selectList(command.getName(), param, rowBounds);
          } else {
            result = sqlSession.<E>selectList(command.getName(), param);
          }
          // issue #510 Collections & arrays support
          if (!method.getReturnType().isAssignableFrom(result.getClass())) {
            if (method.getReturnType().isArray()) {
              return convertToArray(result);
            } else {
              return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
            }
          }
          return result;
        }
      

    那么Mybatis怎么知道是查询的单条数据还是列表呢?

    1. 如果直接使用 SqlSession,这个需要自己控制 是调用 selectOne 还是 selectList
    2. 如果使用 Mapper 接口,Mybatis会解析Mapper接口中的方法,会根据方法的返回值,判断该方法属于那种类型

    解析方法中的参数、返回值

    public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
          Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
          if (resolvedReturnType instanceof Class<?>) {
            this.returnType = (Class<?>) resolvedReturnType;
          } else if (resolvedReturnType instanceof ParameterizedType) {
            this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
          } else {
            this.returnType = method.getReturnType();
          }
          this.returnsVoid = void.class.equals(this.returnType);
          this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());
          this.returnsCursor = Cursor.class.equals(this.returnType);
          this.mapKey = getMapKey(method);
          this.returnsMap = (this.mapKey != null);
          this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
          this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
          this.paramNameResolver = new ParamNameResolver(configuration, method);
        }
    

    method 对象就是 Mapper中的方法

    // select 查询操作
     case SELECT:	
     		// 方法中没有定义返回结果,并且方法存在结果处理器
            if (method.returnsVoid() && method.hasResultHandler()) {
              executeWithResultHandler(sqlSession, args);
              result = null;
            } else if (method.returnsMany()) {
            // 返回列表
              result = executeForMany(sqlSession, args);
            } else if (method.returnsMap()) {
            // 返回Map
              result = executeForMap(sqlSession, args);
            } else if (method.returnsCursor()) {
            	// 返回游标
              result = executeForCursor(sqlSession, args);
            } else {
            // 返回单条数据
              Object param = method.convertArgsToSqlCommandParam(args);
              result = sqlSession.selectOne(command.getName(), param);
            }
            break;
    

    3.返回Map

    返回map 本质上也是返回一个实体。

    	<select id="getUserInfoById"  resultType="map">
    		select * from user where id=#{userId}
    	</select>
    

    如果想要返回单个Map<key,value>集合,只需要设置resultType="map"就可以了,此时返回的实例类型是HashMap
    Map的key就是数据表的列名 或者列别名, value 就是查询的数据库中的结果。如果需要返回LinkedHashMap,需要使用全限定类名resultType="java.util.LinkedHashMap"

    注意: 返回列对应的结果为 null,则不显示该 key - value 键值对(只针对该行数据对应的Map)

    <select id="getStatus"  resultType="map">
    	select '' as  code ,'全部'  as name from dual
    </select>
    

    Oracle环境下:
    在这里插入图片描述
    最终返回Map:

    {"name ":"全部"}
    // code 不是显示
    

    如果使用map接受则不会该map不存在数据. 因为Mybatis默认情况下,不会进行赋值,此时该key-value缺失
    如果需要改变该行为可以在mybatis配置文件中设置

      <setting name="callSettersOnNulls" value="true"/>
    

    callSettersOnNulls 指定当返回结果为null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,注意基本类型(int、boolean等)是不能设置成 null 的。

    配置之后的返回结果:

    {"code":null,"name":"全部"}
    

    4.返回List<Map>

    	<select id="" parameterType="" resultType="map">
    		sql_caluse
    	</select>
    

    resultType设置为map,跟上面一样resultType设置为List集合中元素的类型。

    关于mybatis传递多个参数,可以参考mybatis3-传递多参数

    注意:

    偶然发现Mybatis 会自动对重名的列做去重

    比如我有一组数据,使用Map接受

      SELECT l1.*,l2.*,l3.* FROM ITEM_CAT  l1 LEFT JOIN ITEM_CAT l2 ON l1.Id=L2.PARENT_ID LEFT JOIN ITEM_CAT l3
            ON l2.Id=L3.PARENT_ID WHERE L1.PARENT_ID='0';
    

    在这里插入图片描述

    实际返回结果,会发现 name1,name2 都没有映射到Map中

    [
    	{"parent_id":0,"name":"图书","id":1},
    	{"parent_id":0,"name":"图书","id":1},
    	{"parent_id":0,"name":"图书","id":1},
    	{"parent_id":0,"name":"图书","id":1}
    	......
    ]
    

    稍微修改一下字段名称。

      SELECT l1.*,l2.*,l3.*,'test' as name1 FROM ITEM_CAT  l1 LEFT JOIN ITEM_CAT l2 ON l1.Id=L2.PARENT_ID LEFT JOIN ITEM_CAT l3
            ON l2.Id=L3.PARENT_ID WHERE L1.PARENT_ID='0';
    
    [
    	{"parent_id":0,"name":"图书","id":1,"name1":"test"},
    	{"parent_id":0,"name":"图书","id":1,"name1":"test"},
    	{"parent_id":0,"name":"图书","id":1,"name1":"test"},
    	{"parent_id":0,"name":"图书","id":1,"name1":"test"}
    	......
    ]
    

    可以看到 新增的自定义列名 “name1”,可以正常显示。这是因为使用sql 查询出的同名的列名自动追加数字做区分,而实际保存在 元数据信息中的列名还是原来的。就如同Excel 的单元格一样,不管单元格内容以什么样式显示都不会修改实际值。
    在这里插入图片描述

    在这里插入图片描述

    小结:

    • 返回集合与返回单个实体对象在映射文件的写法是一致的,不同的地方在于Mapper的返回类型不同。
    • 如果不确定返回值是否是唯一的,尽量使用 集合的返回方式。然乎使用get(0)的方式获取实体。
    • 如果返回实体,一般情况会使用 resultMap来映射返回结果。这样更清晰,直观,而且还可以使用typeHandler对数据类型做进一步处理
    返回结果Mapperxml
    实体T getT()returnType=“T”
    集合List<T> getTList()returnType=“T”
    展开全文
  • 场景: 最近在写接口时候,正常使用@RestController返回json串,发现当返回的对象里的属性值为空字符串或者null时候,json返回里就会自动去除这个key,啥意思呢?举个"栗子": /** * 商品评论、回复、点赞【查询】...

    场景: 最近在写接口时候,正常使用@RestController返回json串,发现当返回的对象里的属性值为空字符串或者null时候,json返回里就会自动去除这个key,啥意思呢?举个"栗子":

    /**
         * 商品评论、回复、点赞【查询】接口
         *
         * @param goodsId
         * @param userId
         * @param currenPage
         * @param pageSize
         * @return
         * @author simons.fan
         */
        @GetMapping("/get-comments-replys")
        public Response getCommentsAndReplys(
                @RequestParam(value = "goodsid", required = false) Long goodsId,
                @RequestParam(value = "userid", required = false) Long userId,
                @RequestParam(value = "currenpage", defaultValue = "1", required = false) Integer currenPage,
                @RequestParam(value = "pagesize", defaultValue = "20", required = false) Integer pageSize) {
            log.info("商品评论查询接口入参:[goodsid={},userid={},currentpage={},pagesize={}]", goodsId, userId, currenPage, pageSize);
            if (goodsId == null || userId == null)
                return new Response(BaseCodeEnum.PARAMETER_MISS, null);
            try {
                PageBean<CommentsResultVo> commentPageBean = goodsService.getCommentsAndReplys(
                        ImmutableMap.of(
                                "userId", userId,
                                "goodsId", goodsId,
                                "currentPage", currenPage,
                                "pageSize", pageSize
                        ));
                return new Response(BaseCodeEnum.SUCCESS, commentPageBean);
            } catch (Exception e) {
                log.error("商品评论查询接口异常:[userid={},goodsid={},ex={}]", userId, goodsId, e);
            }
            return new Response(BaseCodeEnum.ERROR, null);
        }

    CommentsResultVo部分属性为:

    @Data
    public class Comment {
        private Long id;
        private Long goodsId;
        private Long userId;
        private String commentMsg;
        private Long likeCount;
        /**
         * 用户名
         */
        private String userName;
        /**
         * 用户头像url
         */
        private String avatarUrl;
        /**
         * 用户昵称
         */
        private String userNickName;
    }

    这么一个方法,预期返回的json应该是:即当avatarUrl为空时候,avatarUrl这个key也必须存在(因为接口的响应报文里面字段非常多,我这里去除了很多字段,主要是一种规范,也是为了前端方便调用)

    可实际情况是,当CommentResultVo类里面的某些属性为空或null时候,比如 avatarUrl属性值为空,json串就直接去掉了这个avatarUrl这个key,不够友好。众所周知,springmvc里默认是使用jackson来处理返回的json对象的,一顿源码找,发现不会过滤掉才对的,纳闷,忽然间看到了项目里存在如下代码:

    @Configuration
    public class WebConfiguration {
        /**
         * 使用fastjson解析对象返回数据
         *
         * @return
         */
        @Bean
        public HttpMessageConverters fastJsonHttpMessageConverters() {
            FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
            FastJsonConfig fastJsonConfig = new FastJsonConfig();
            fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
            List<MediaType> fastMediaTypes = new ArrayList<>();
            fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
            fastConverter.setSupportedMediaTypes(fastMediaTypes);
            fastConverter.setFastJsonConfig(fastJsonConfig);
            HttpMessageConverter<?> converter = fastConverter;
            return new HttpMessageConverters(converter);
        }
    }

    问题就在这里,有个同事显式的设置了fastjson来替代默认的jackson处理json返回,这下就好办了,加上新增的序列化方式SerializerFeature.WriteNullStringAsEmpty 即可顺利解决我的问题:

    fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.PrettyFormat);
    

    上述是在springboot中操作的,xml方式如下:

    注:图片取自网络

    这种需求是很常见的,value值为空,key也得返回,这样前端可以很友好的处理你的json。

    延伸出来的问题有:

    1、当返回的集合类型为空也要包含[ ],例如   "commentList":[ ],而不是 "commentList":null 或"commentList":" ";

    2、属性为空,自动给属性对应值赋值为默认的缺省值,比如userId是Long类型,如果为空就自动赋值为0,userName是String,为空则自动赋值为"",而不是null;

    当然,有些接口比较特殊,它就是需要和上面相反的做法:当key为空或null,这个字段就不需要返回,这个话,可以借助JackSon的@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)注解,加在实体类上即可。

    今天暂时就先写这么多吧,忙工作,后面抽时间续写……未完待续……


    引申阅读

    books Json和Bean间的序列化和反序列化(JSONObject、Gson、FastJson的使用):https://love1024.blog.csdn.net/article/details/78246870

    展开全文
  • 刚才是使用redirectTo 方法 /** * 生命周期函数--监听页面卸载 */ onUnload: function () { ...但是这样出现一个问题 就是先返回瞬间返回点击跳转的界面在跳到指定界面,,, 是不是感觉怪怪的,,, ...

    刚才是使用redirectTo 方法

      /**
       * 生命周期函数--监听页面卸载
       */
      onUnload: function () {
        wx.redirectTo({
          url: '../index/two/two',//指定界面
        })
      },

    但是这样出现一个问题 就是先返回瞬间返回点击跳转的界面在跳到指定界面,,,

    是不是感觉怪怪的,,,

    处理方法就是自定标题栏然后监听返回键自己写跳到摸一个界面跳转方法建议使用wx.reLaunch 

    自定义标题栏的方法参考链接

    不过跳转界面就别用navigateTo 方法了,它会是返回的几面带返回键

     所以呢建议使用wx.reLaunch 

    展开全文
  • Mybatis-Plus插入数据返回主键值的参考如下: ![图片说明](https://img-ask.csdn.net/upload/202009/15/1600150795_577490.png) ##### 配置后,确实返回了插入记录的id值。 ##### 但是,我发现,即便不配置,...
  • 1.微信公众号交互页面嵌入了JSP页面,微信内置的浏览器下方有前进、后退按钮,安卓版没有,IOS会有,在实际项目中,有页面跳转A-->B-->C,C页面做完处理点击返回直接跳到A页面的需求,默认的返回是不可以的,处理...
  • 返回对象的值则返回的是对象的副本,对对象副本的修改不会影响原对象。 返回对象的值示例。 package main import ( "fmt" ) type Men interface { Print() Set() } type Employee struct { company ...
  • Python——返回函数

    千次阅读 2018-08-16 12:03:33
    返回函数 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。 &gt;&gt;&gt; def lazy_sum(*args): ... def sum(): ... z = 0 ... for i in args: ... z += i ... ret...
  • mybatis添加返回主键

    万次阅读 2019-11-23 23:02:51
    mybatis添加返回主键 两种方法 <!--返回主键方法一--> <insert id="save" parameterType="baidu.com.pojo.THobby" useGeneratedKeys="true" keyProperty="hid"> insert into t_hobby set hobby=#{...
  • 包含一个SSH框架实例和一个获取该服务器返回json数据的android app实例。 使用方法, 1.SHH是SSH框架的java wab工程,里面定义了一个action,启动apach-tomcat服务器后可在浏览器输入“localhost:8080/SSH/userjson...
  • 超级简单,入门级 命令cd cd .. 返回上一级目录 cd ../.. 返回上两级目录 cd或cd ~ 返回home目录 cd / 返回根目录 cd - 返回刚才的目录 cd - 目录名 返回指定目录 ...
  • 有时候返回,他不是跳转到首页,我们这里就要加一个监听函数。就在你写的对应的页面加,不是在pages.json里面加哦 onBackPress(event){ uni.redirectTo({ url:'../index/index' }); return true; }, ...
  • 各位大佬求教个问题,怎么实现点手机的实体的返回键不会退出程序只是回到桌面,我现在用WillPopScope监听到了返回键操作然后设置返回无效,但是不知道怎么实现回到桌面。感谢。 ``` Future<bool> _...
  • C++返回对象和返回引用

    千次阅读 2017-12-27 23:48:27
    我们发现,在C++中,有些成员函数返回的是对象,而有些函数返回的又是引用。 返回对象和返回引用的最主要的区别就是函数原型和函数头。 Car run(const Car &) //返回对象 Car & run(const Car &) //返回...
  • 注意一定要在success后面加上.bind(this)代码,不然ios端会出现,点击物理返回键后,先退出该页面在出现弹框的问题。 亲测有效(ios端和android端已测) onBackPress() { //console.log("press back"); uni....
  • Controller返回Json数据

    千次阅读 2019-09-15 14:48:41
    @Controller public class ItemController { @Autowired private ItemService itemService; @RequestMapping("/item/{... 使用@ResponseBody 可以返回Json数据 */ @ResponseBody public TbItem getItemById...
  • MyBatis返回类型

    千次阅读 2019-06-10 18:14:01
    分类及返回值类型 对应的分类为 resultMap resultType 对应返回值类型 resultMap:结果集 resultType:int,string ,long ,class ...在MyBatis进行查询映射...1、当提供的返回类型属性是resultType时,MyBatis会将Ma...
  • Android自定义标题栏(并加入返回按钮)demo

    千次下载 热门讨论 2011-10-12 11:08:31
    Android自定义标题栏(并加入返回按钮)的demo
  • PostgreSQL定义返回表函数

    千次阅读 2019-05-18 16:03:37
    PostgreSQL定义返回表函数 本文我们学习如何在PostgreSQL 开发返回表函数。 示例数据表 我们使用的示例数据库表为film,如下图所示: 示例1 第一个函数发挥所有满足条件film表记录,这里使用ilike操作,和like类似...
  • HTTP 返回码详解

    万次阅读 2018-06-09 20:52:00
    200 服务器成功返回网页 404 请求的网页不存在 503 服务不可用1xx(临时响应)表示临时响应并需要请求者继续执行操作的状态代码。100(继续)请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分...
  • 在controller方法中返回到前端的数据类型多变,比如校验验证码是返回 Boolean数据类型, 分页数据是返回 List 数据类型 等, 多个返回类型使得前端与 后端人员的交流复杂起来, 而统一规约一个返回到前端的数据格式,就...
  • VC++实现CMD命令执行与获得返回信息

    千次下载 热门讨论 2010-09-09 16:37:40
    VC++6.0实现CMD命令执行与获得返回信息,用CreateProcess执行CMD命令,用命名管道来获得返回的数据.基本上可以执行所有CMD命令.
  • uniapp关闭默认返回安卓和ios

    千次阅读 2021-09-24 11:19:45
    ios页面有默认手势关闭页面,需要在page.json配置单个页面或整个应用关闭ios的手势返回,那它就只能走我们的导航栏关闭了,就能监听了。 { "path": "pages/xxx", "style": { "navigationBarTitleText": "xx
  • 序言   在ios7以后,苹果推出了手势滑动返回功能,也就是从屏幕左侧向右滑动可返回上一个界面。大大提高了APP在大屏手机和iPad上的操作体验,场景切换更加流畅。做右滑返回手势配置时,可能会遇到的问题:   1....
  • Linux 返回根目录,返回主目录

    千次阅读 2019-12-21 22:19:59
    1.返回根目录 cd / 2.返回主目录 cd ~
  • Python 查找返回所有下标

    千次阅读 2019-06-07 13:04:14
    返回所有符合条件的下标,自然想到的是用列表解析(list comprehension),并在列表解析中增加一个断言(if pred,是否符合条件),那么又该如何返回其下标呢,是使用 index() 成员函数吗? 比如,我们要获取列表中...
  • 在一个H5页面,让浏览器与APP不能返回这个页面,类似于一个恶心的广告页面 代码: XBack = {}; (function(XBack) { XBack.STATE = 'x - back'; XBack.element; XBack.onPopState = function(event) { ...
  • 在Fragment中监听返回

    千次阅读 2017-08-30 15:22:45
    如图所示:当我需要处理fragment的返回事件时,我先处理fragment中的逻辑,不需要时,直接交给activity处理即可。其实实现的方式很简单,就是在activity中调fragment的返回事件即可。代码示例: 首先我们写项目的...
  • //禁止页面后退 history.pushState(null,null,document.URL); window.addEventListener('popstate',function(){ //监听浏览器的返回事件 history.pushState(null,null,document.URL); });
  • flutter 页面返回时刷新页面

    千次阅读 2020-05-08 17:23:06
    1、在使用 Navigator.of(context).pop("xxxx"); 方法时,传值过去,xxxx随便传什么内容 2、在跳转到本页面之前的一个页面中 Navigator.push( context, MaterialPageRoute(builder: (context) =>...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,625,510
精华内容 3,450,204
关键字:

返回