zoukankan      html  css  js  c++  java
  • spring data jpa 查询自定义字段,转换为自定义实体

    目标:查询数据库中的字段,然后转换成 JSON 格式的数据,返回前台。

    环境:idea 2016.3.4, jdk 1.8, mysql 5.6, spring-boot 1.5.2 
    背景:首先建立 entity 映射数据库(非专业 java 不知道这怎么说)

    @Entity
    @Table(name = "user")
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        private String userName;    // 账号
        private String password;    // 密码
        // getter setter 方法略过
    }
    

      

    然后建立与之对应的 model

    public class UserModel implements Serializable {
        // 一些属性
    }

    这里我们分情况讨论

    首先第一种情况:查询的字段与表中的字段全部对应(就是查表里所有的字段,但是使用 Model 作为接收对象)

    这种情况比较简单,调用 Repository 提供的方法,返回一个 entity , 然后将 entity 的属性复制到 model 中。像这样

    UserModel user = new UserModel();
    User userEntity = new User();
    // 一个工具类,具体使用方法请百度
    BeanUtils.copyProperties(user, userEntity);

    第二种情况:只查询指定的几个字段

    现在我有张表,有字段如下:

    @Entity
    @Table(name = "user_info")
    public class UserInfo {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        private String name = "用户";     // 昵称
        private String signature;         // 个性签名
        private String gender = "未知";   // 性别
        private String description;       // 个人说明
        private String avatar;            // 头像
        private Long role;                // 权限
        private Boolean disable;          // 是否冻结
        private Date createTime;          // 创建时间
        private Boolean isDelete;         // 是否删除
        private Long userId;              // 用户 Id
        // ...
    }

    但是我只需要查询指定的几个字段,然后转换成 JSON,返回给前台,咋办呢?

    第一种方法:使用 model 查询时转化

    首先建立一个 model ,写上自己想要查询的字段,然后写上构造函数,这步很重要,因为spring jpa 转化时会调用这个构造方法

    public class MyModel implements Serializable {
    
        private String userName;
        private String name;
        private String gender;
        private String description;
    
        public MyModel() {};
    
        public MyModel(String userName, String name, String gender, String description) {
            this.userName = userName;
            this.name = name;
            this.gender = gender;
            this.description = description;
        }
    }

    然后在 dao 类中写查询方法

    @Query(value = "select new pers.zhuch.model.MyModel(u.userName, ui.name, ui.gender, ui.description) from UserInfo ui, User u where u.id = ui.userId")
    public List<MyModel> getAllRecord();

    直接在查询语句中 new model 框架底层会调用它,然后返回这个对象(这里我写了完整的类路径,不写的时候它报错说找不到类型什么的)

    然后就可以获得只有指定字段的 model 了。然后就把它转成 JSON 格式就 O 了。

    第二种方法:在service 里边转换成 JSON

    原理其实和第一种方法差不多,只是处理结果的方式不太一样,只是这种方法我们就不在 hql 中 new Model 了,直接写查询方法

    @Query(value = "select new map(u.userName, ui.name, ui.gender, ui.description) from UserInfo ui, User u where u.id = ui.userId")
    public List<Map<String, Object>> getCustomField();

    直接new map(这里得是小写,不知道大写有木有问题,反正没试,编译器提示是要小写的) 
    然后返回的结果是这样的

    [
        {
            "0": "admin", 
            "1": "你猜", 
            "2": "男", 
            "3": "一段描述"
        }, {
            "0": "abc", 
            "1": "你猜人家", 
            "2": "女", 
            "3": "没事先挂了"
        }
    ]

    然后在 service 层里直接封装成 JSON 对象,返回

    List<JsonObject> list = new ArrayList();
    for(Map map : result) {
        JsonObject j = new JsonObject();
        j.addProperty(attrName, val);
        ...
        list.add(j);
    }
    gson.toJson(list);

    还有一种返回结果,这样写:

    @Query(value = "select u.userName, ui.name, ui.gender, ui.description from UserInfo ui, User u where u.id = ui.userId")
    public List<Object> getCustomField();

    返回结果是这样的格式:

    [
        [
            "admin", 
            "你猜", 
            "男", 
            "一段描述"
        ], [
            "abc", 
            "你猜人家", 
            "女", 
            "没事先挂了"
        ]
    ]

    返回的是数组,也一样可以通过上面的方法转成 json ,这里我的程序中出现了一点点 BUG,就是空值的字段不会在数组中,不知道为什么。

    这种方法必须明确的知道查询了哪些字段,灵活性比较差,虽然它解决了手头的问题。还有就是版本的不同,有可能会出现丢失空字段的情况,我个人特别的不喜欢这样的方法,万一我实体几十个字段,写着写着忘了写到哪了,就 over 了

    第三种方法:返回一个便于转换成 json 格式的 list

    其实和上面很相似,都是 dao 层返回一个 List < Map < String, Object >>,但是上面的结果集返回的 Map 的 key 只是列的下标,这种方式稍微理想一点点,就是 Map 的 key 就是查询的列名。但是这种方式需要实现自定义 Repository( 这里不详细介绍,请自行百度 ),并且只是 jpa 集成 hibenate 的时候可以使用。

    public List getCustomEntity() {
        String sql = "select t.id, t.name, t.gender, t.is_delete, t.create_time, t.description from t_entity t";
        Query query = em.createNativeQuery(sql);
        // Query 接口是 spring-data-jpa 的接口,而 SQLQuery 接口是 hibenate 的接口,这里的做法就是先转成 hibenate 的查询接口对象,然后设置结果转换器
        query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        return query.getResultList();
    }

    这种方法返回的就是比较标准的 JSON 格式的 java 对象了,只需要用 jackson 或者 Gson 转一下就是标准的 json 了

    [
        {
            attr: val,
            ...
        },
        {
            attr: val,
            ...
        },
    ]

    这种方式其实已经比较理想了,因为直接就能返回到前台,但是有时候,结果不是一条 sql 能够解决的,得两条或者以上的 sql 来解决一个复杂的查询需求,这个过程中,结果比较需要转换成 pojo,以便于组装操作。

    第四种方案:dao 中直接转成 pojo 返回

    这个方案还是依赖于 hibenate,有点操蛋,但是更明确一些。

    public List getCustomEntity() {
        String sql = "select t.id, t.name, t.gender, t.is_delete as isEnable, t.create_time as createTime, t.description from t_entity t";
        Query query = em.createNativeQuery(sql);
        query.unwrap(SQLQuery.class)
        // 这里是设置字段的数据类型,有几点注意,首先这里的字段名要和目标实体的字段名相同,然后 sql 语句中的名称(别名)得与实体的相同
                .addScalar("id", StandardBasicTypes.LONG)
                .addScalar("name", StandardBasicTypes.STRING)
                .addScalar("gender", StandardBasicTypes.STRING)
                .addScalar("isEnable", StandardBasicTypes.BOOLEAN)
                .addScalar("createTime", StandardBasicTypes.STRING)
                .addScalar("description", StandardBasicTypes.STRING)
                .setResultTransformer(Transformers.aliasToBean(EntityModel.class));
        return query.getResultList();
    }

    这次返回的就是 List 了。这里要注意的是 StandardBasicTypes这个常量类,在一些旧版本中,是 Hibenate 类,具体哪个包我不知道,我这个版本中是换成了前面的那个常量类

  • 相关阅读:
    php 高精度计算函数
    CSS 文本溢出显示省略号样式
    Vue import、export及export default示例详解,附带如何实现全局调用
    利用高德API获取最新的省市区数据
    TP5 基类验证器
    php 两种递归方法
    新建PO類型ZFA的固定資產時灰掉 GR Non-Valuated
    MRP 參數設置
    info record
    kill procedure in os level
  • 原文地址:https://www.cnblogs.com/icebutterfly/p/9516199.html
Copyright © 2011-2022 走看看