一些程序封装的疑问

2020-04-23 15:42:13 +08:00
 basefas

例如一个获取用户信息的功能,但是可能不同接口需要不同的字段。假设 user 表包含 id, created_at, updated_at, username, password, email 字段,一个接口需要 idusername,另一个接口需要 usernameemail,项目为普通的 mvc 架构,controller 层提供接口,service 层对接 controller 和数据库,现在我能想到的有三种方式,不知道大家平时都怎么使用。

  1. service 层方法查出 user 的全部字段,在 controller 层通过创建新 object,将所需字段赋值给 object
  2. service 层方法参数和返回值设置为 interface,在 controller 层调用时将需要查询的 object 作为参数传入
  3. service 层写两个方法,分别返回不同 object

1 的问题在于需要做额外的赋值操作,2 的话入参结构有不确定性,可能引起问题,3 的话主要是会多些重复代码,但是能保证方法返回可预期,个人比较倾向方法 3 。 其实还有方法 4 就是什么都不处理都返回去,让调用方筛选,不过这个被直接 pass 了。

3252 次点击
所在节点    程序员
30 条回复
lhx2008
2020-04-23 15:57:17 +08:00
把隐藏的字段置空,序列化的时候隐藏
lhx2008
2020-04-23 15:59:35 +08:00
第二个是 controller 序列化的时候加一个策略,传入一个配置来控制序列化器的行为
lhx2008
2020-04-23 16:00:30 +08:00
第三个方法就是配多个 VO 对象,在 controller 转换
basefas
2020-04-23 16:11:45 +08:00
@lhx2008 你说的这些都是在 service 层把所有字段都查出来,在 controller 层做格式化是么?
cxe2v
2020-04-23 16:48:43 +08:00
1,3 都可,不建议用 2
KentY
2020-04-23 16:53:28 +08:00
为什么不能把包含所有字段的 object 给不同请求方呢? 他不需要可以不用呀.
如果一些信息的保密 /屏蔽是必须的, 那不管怎么都需要另外一步, 要么屏蔽相关信息, 要么 convert into other objects
johnj
2020-04-23 17:02:25 +08:00
如果你用的是 Spring MVC,那么可以用 Jackson 的 JSON View 注解 @JsonView

1 做一个分类的类(名称随便)
public class Views {
public static class Public {
}

public static class Internal {
}
}
2 根据分组 在 User 对象属性上加注解 如 @JsonView(Views.Public.class)
3 在 controller 方法上 确定要返回的分组 如 @JsonView(Views.Public.class)

参考: https://www.baeldung.com/jackson-json-view-annotation
basefas
2020-04-23 17:03:02 +08:00
@KentY 总体思想是尽量保持简洁,保持接口返回数据的最小化(说白了就是一种强迫症)。比如 user 表可能有 50 个字段,但是有时候可能只想要一个用户 ID,那返回数据中大部分就都没有用,还占带宽。还有就是例子中说的,可能会有 created_at 这种字段,一般情况下是不想直接返回给请求方的。
lhx2008
2020-04-23 17:03:52 +08:00
@basefas 如果对象查询次数不多的话不用专门写 service
basefas
2020-04-23 17:06:17 +08:00
@johnj 虽然没用过 Spring MVC,但是这个思想就是用一个 model 都查出来,然后在 controller 层处理数据吧
johnj
2020-04-23 17:08:08 +08:00
@basefas 对的 service 不应该管上层的事
johnj
2020-04-23 17:09:06 +08:00
@basefas 哦 你不是 java 栈的 那这些方法应该不适用了 看你用的序列化库有什么样的支持吧
KentY
2020-04-23 17:09:09 +08:00
@basefas 如果没有实质的业务需求, 我觉得这样没太大必要. 返回值简捷并不算简捷(从某种意义讲).
比如需要 id, uid 的请求某天说, 我们想要姓氏, 那你后端就要重新改动部署. 这是完全没必要的. 至于带宽性能方面, 我不知道你们的项目是多么的 performance critical, 按一般情况讲, 这点带宽不算什么.

当然了, 我没了解你的项目需求, 只是说看到这个问题的一般感觉. 特殊情况是需要特殊对待.
basefas
2020-04-23 17:10:01 +08:00
@johnj 嗯嗯,也是一种思路
basefas
2020-04-23 17:12:06 +08:00
@KentY 嗯,你说的有道理,我也没有具体的需求,只是考虑在没有限制条件的情况下,怎么写才比较优雅。
wutiantong
2020-04-23 17:51:55 +08:00
记好 kiss 原则
vitoliu
2020-04-23 17:53:47 +08:00
public class Simple{}
public class Medium extends Simple{}
public class Hard extends Medium{}
WUWENZE
2020-04-23 18:04:12 +08:00
这种需求我弄过,使用的是注解+拦截器,内部实现是 Fastjson 的 JSONSerializer

最终的效果就像这样
```java

@ApiResponseFilters({ //
@ApiResponseFilter(clazz = UserVO.class, includeFields = "id,name,nickname,photo,type"), //
@ApiResponseFilter(clazz = UserGroupVO.class, includeFields = "id")
})



```
aguesuka
2020-04-23 18:06:10 +08:00
我也有类似需求。系统有 3 张核心表,这三张核心表 join 其他十多张表可以查出来一条完整的数据。系统里大部分操作就是核心表 join 若干非核心表分页条件动态查询。现在我就想写一个 god 方法,根据前台要查的字段,要过滤的条件自动生成最优 sql,想了想难度不亚于实现个 orm 还是算了。
WUWENZE
2020-04-23 18:08:49 +08:00
@aguesuka 你可能需要的是 https://graphql.cn/

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/665355

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX