面试官:有一个 List 对象集合,如何优雅地返回给前端?我懵了~

文摘   2024-11-10 11:01   陕西  
今天我们来聊聊一个面试中的经典问题:“如何优雅地返回给前端一个 List 对象集合?”这个问题表面上看起来简单,但如果你稍微考虑一下背后的数据结构设计和优化,就能发现其实有不少值得深思的地方。
今天,我就来给大家详细解读一下这道题,并为你们提供一个优雅的解决方案。

1. 问题描述

在面试中,我们经常会碰到这种问题:前端想要的数据格式是包含多个场景的集合,但是在数据库或者业务逻辑层,数据格式有些不太“整洁”。比如,sessionId 重复出现在多个场景数据中,导致了冗余。
想象一下,如果我们每次都返回一个包含大量重复 sessionId 的数据给前端,前端不仅要处理这些冗余数据,还可能会面临性能问题。
那么,如何才能优化这种结构,减少冗余,同时保持数据的清晰与易用呢?

2. 期望的数据结构

我们希望能够将 sessionId 提取到数据结构的外层,同时将多个场景放到 sceneList 中。这样做的好处是:
  • 清晰性:前端能够直接获取到 sessionId,并且多个场景会在 sceneList 中存储,简洁明了。
  • 减少冗余:避免 sessionId 在每个场景中重复出现,减少不必要的数据传输。
修改后的数据结构示例如下:
{
  "sessionId""12345",
  "sceneList": [
    {
      "sceneId""A1",
      "sceneName""Scene 1",
      "description""This is the first scene."
    },
    {
      "sceneId""A2",
      "sceneName""Scene 2",
      "description""This is the second scene."
    }
  ]
}
可以看到,我们把 sessionId 提取到外层,sceneList 存储的是所有相关的场景信息,这样就避免了每个场景中都包含 sessionId

3. 优化后的实体类设计

为了实现这种结构,我们需要重新设计实体类。这里,我们定义两个类:SceneVOSubSceneVO
  • **SceneVO**:包含 sessionIdsceneList
  • **SubSceneVO**:表示单个场景的信息,包含 sceneIdsceneNamedescription 等属性。

实体类设计如下:

public class SceneVO {
    private String sessionId;   // sessionId 提取到外层
    private List<SubSceneVO> sceneList;  // 存储多个场景

    // Getter 和 Setter
}

public class SubSceneVO {
    private String sceneId;
    private String sceneName;
    private String description;

    // Getter 和 Setter
}

4. 自定义 MyBatis Mapper 和 XML 配置

接下来,我们需要在 MyBatis 中进行配置,以便能够从数据库中查询并正确映射数据。首先,我们定义一个 Mapper 接口,其中包含查询数据的方法,比如 selectBySessionId

Mapper 接口:

public interface SceneMapper {
    List<SubSceneVO> selectBySessionId(String sessionId);
}
然后,在 MyBatis 的 XML 配置中,我们使用 <collection> 标签来映射 sceneList。这样,MyBatis 会根据 sessionId 查询出所有场景,并将它们映射到 sceneList 中。

MyBatis XML 配置:

<resultMap id="sceneResultMap" type="SceneVO">
    <id property="sessionId" column="session_id"/>
    <collection property="sceneList" ofType="SubSceneVO">
        <result property="sceneId" column="scene_id"/>
        <result property="sceneName" column="scene_name"/>
        <result property="description" column="description"/>
    </collection>
</resultMap>

<select id="selectBySessionId" resultMap="sceneResultMap">
    SELECT session_id, scene_id, scene_name, description
    FROM scenes
    WHERE session_id = #{sessionId}
</select>

5. Service 层设计

在 Service 层,我们需要定义接口 SceneService,并实现 SceneServiceImpl。通过调用 Mapper 层的方法,我们将数据库查询的数据传递到 Controller 层,最终返回给前端。

Service 接口:

public interface SceneService {
    SceneVO getScenesBySessionId(String sessionId);
}

Service 实现:

@Service
public class SceneServiceImpl implements SceneService {
    
    @Autowired
    private SceneMapper sceneMapper;

    @Override
    public SceneVO getScenesBySessionId(String sessionId) {
        SceneVO sceneVO = new SceneVO();
        sceneVO.setSessionId(sessionId);
        sceneVO.setSceneList(sceneMapper.selectBySessionId(sessionId));
        return sceneVO;
    }
}

6. Controller 层设计

最后,我们来设计 Controller 层,处理前端的请求并调用 Service 层。假设前端请求的 URL 是 /scenes/{sessionId},Controller 会获取 sessionId,然后调用 SceneService 返回结果。

Controller 示例:

@RestController
@RequestMapping("/scenes")
public class SceneController {

    @Autowired
    private SceneService sceneService;

    @GetMapping("/{sessionId}")
    public SceneVO getScenes(@PathVariable String sessionId) {
        return sceneService.getScenesBySessionId(sessionId);
    }
}

7. 总结

通过优化实体类设计和数据结构,我们不仅让代码更加简洁清晰,还大大提高了前端获取数据的效率。将 sessionId 提取到外层,避免冗余,并通过合适的 MyBatis 配置与 Service 层设计,将数据以优雅的方式返回给前端。

8. 扩展与优化建议

  • 分页查询:对于数据量较大的场景列表,可以考虑引入分页查询,避免一次性查询大量数据。
  • 缓存优化:可以通过引入缓存(如 Redis)来加速查询,特别是在查询结果不频繁变化的情况下。
这篇文章的核心思路就是优化数据结构,将重复信息提取到外层,减少前端处理的复杂度。通过合理的设计,我们不仅让代码更加高效、易于维护,还能提升整个系统的可扩展性。
如果面试时遇到类似的问题,你可以直接给出这种优化思路,并通过实际的代码示例展示自己的解决能力。
希望大家今天学到的东西能帮到你们,也欢迎大家在评论区分享自己的思路和经验。加油!

-END-

ok,今天先说到这,老规矩,看完文章记得右下角给何老师点赞。

最后送给大家一个福利,我这里有一份搞副业的教程,这份教程里有100+个搞钱小项目

网盘拉新核心玩法、公众号运营变现、小红书虚拟资料引流等,现在扫码加我微信,即可领取这份副业教程。

添加时备注:副业

程序员老鬼
10年+老程序员,专注于AI知识普及,已打造多门AI课程,本号主要分享国内AI工具、AI绘画提示词、Chat教程、AI换脸、Chat中文指令、Sora教程等,帮助读者解决AI工具使用疑难问题。
 最新文章