基于mybatis-plus实现一个自己设计的GET接口

一、前期环境准备

由于并不打算从零开始,只是为了验证一下我设计的接口。所以最便捷的方法是使用一个用了mybatis-plus的项目,github上随便找,从里面开始着手,而且数据库我已经建立好了。

二、接口设计:展示所有信息的列表

类型 GET
描述 : 查询出所有单位的详细信息
请求参数:无
URL http://127.0.0.1:8080/api/show-all-tasks
Response

{

  "status": 200,

  "message": "Success",

  "tasks": [

    {

      "case_id": "0001",

     ......

      "upload_time": "2023-10-01T12:00:00Z",

      "data_overview": {

        "app_cpu_avg": "20",
		 ......

        "b_temp_range": "25"

      }

    },

    {

      "case_id": "0002",

      ......

      "upload_time": "2023-10-02T12:00:00Z",

      "data_overview": {

        "app_cpu_avg": "25",
 		......
        "b_temp_range": "28"

      }

    },

    {

      "case_name": "用例3",

      ......
      "upload_time": "2023-10-03T12:00:00Z",

      "data_overview": {

        "app_cpu_avg": "32",

       ......

        "b_temp_range": "34"

      }

    }

  ]

}


三、详细步骤

1.接口分析
这个接口涉及到多表查询,用entity肯定不能实现我的需求,到底是用VO还是DTO呢?

选择VO还是DTO
VO(View Object):
用途:主要用于前端展示,包含前端需要展示的所有数据。
特点:通常包含较多的字段,可能包含一些计算或聚合的数据。

DTO(Data Transfer Object):
用途:主要用于数据传输,包含后端与前端之间传输的数据。
特点:通常包含较少的字段,只包含必要的数据。

根据我的接口设计,响应包含了多个字段,包括任务信息和数据概览,这些数据可能来自多个表。因此,使用VO更为合适,因为它可以包含所有前端需要展示的数据。

1.设计出我的VO:

TaskVO.java

package cn.ityao.cat.vo;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.Date;

@Data
public class TaskVO {

    /**
     * 用例编号
     */
    private String caseId;
    //...........
    //注意和数据库中的字段对齐

    /**
     * 上传时间
     */
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'", timezone = "GMT+8")
    private Date uploadTime;

    /**
     * 数据概览
     */
    private DataOverviewVO dataOverview;
}

2.controller 层
TaskController.java

package cn.ityao.cat.controller;
import cn.ityao.cat.service.TaskService;
import cn.ityao.cat.vo.TaskVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api")
public class TaskController {

    @Autowired
    private TaskService taskService;

    @GetMapping("/show-all-tasks")
    public ResponseEntity<Map<String, Object>> showAllTasks() {
        List<TaskVO> tasks = taskService.getAllTasks();
        Map<String, Object> response = new HashMap<>();
        response.put("status", 200);
        response.put("message", "Success");
        response.put("tasks", tasks);
        return ResponseEntity.ok(response);
    }
}

3.service 层
TaskService.java

package cn.ityao.cat.service;
import cn.ityao.cat.vo.TaskVO;

import java.util.List;

public interface TaskService {
    List<TaskVO> getAllTasks();
}

TaskServiceImpl.java

package cn.ityao.cat.service.impl;
import cn.ityao.cat.mapper.TaskMapper;
import cn.ityao.cat.service.TaskService;
import cn.ityao.cat.vo.TaskVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TaskServiceImpl implements TaskService {

    @Autowired
    private TaskMapper taskMapper;

    @Override
    public List<TaskVO> getAllTasks() {
        return taskMapper.selectAllTasks();
    }
}


4.mapper 层
TaskMapper.java

package cn.ityao.cat.mapper;
import cn.ityao.cat.common.DataOverviewTypeHandler;
import cn.ityao.cat.entity.Task;
import cn.ityao.cat.vo.DataOverviewVO;
import cn.ityao.cat.vo.TaskVO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.type.JdbcType;

import java.util.List;

public interface TaskMapper extends BaseMapper<Task> {

    @Select("SELECT t.*, d.device_mode, d.platform " +
            "FROM case_list_table t " +
            "JOIN device_detail_table d ON t.device_id = d.device_id")
    @Results({
            @Result(column = "data_overview", property = "dataOverview", javaType = DataOverviewVO.class, jdbcType = JdbcType.VARCHAR, typeHandler = DataOverviewTypeHandler.class)
    })
    List<TaskVO> selectAllTasks();
}

四、疑惑和思考

1️⃣数据库中的json字段如何匹配实体类?

1.使用一个VO专门对应json中的字段
2.使用转换类
package cn.ityao.cat.common;
import cn.ityao.cat.vo.DataOverviewVO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(DataOverviewVO.class)
public class DataOverviewTypeHandler extends BaseTypeHandler<DataOverviewVO> {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, DataOverviewVO parameter, JdbcType jdbcType) throws SQLException {
        try {
            ps.setString(i, objectMapper.writeValueAsString(parameter));
        } catch (JsonProcessingException e) {
            throw new SQLException("Error converting DataOverviewVO to JSON string", e);
        }
    }

    @Override
    public DataOverviewVO getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String json = rs.getString(columnName);
        return json == null ? null : fromJson(json);
    }

    @Override
    public DataOverviewVO getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String json = rs.getString(columnIndex);
        return json == null ? null : fromJson(json);
    }

    @Override
    public DataOverviewVO getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String json = cs.getString(columnIndex);
        return json == null ? null : fromJson(json);
    }

    private DataOverviewVO fromJson(String json) {
        try {
            return objectMapper.readValue(json, DataOverviewVO.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Error converting JSON string to DataOverviewVO", e);
        }
    }
}


3.//另外配置在mapper中
@Results({
            @Result(column = "data_overview", property = "dataOverview", javaType = DataOverviewVO.class, jdbcType = JdbcType.VARCHAR, typeHandler = DataOverviewTypeHandler.class)
    })

2️⃣接口响应为啥没有时间这一栏?

因为在实体类的时间属性设置了@JsonProperty(access = JsonProperty.Access.WRITE_ONLY):
这个注解设置access属性为WRITE_ONLY,意味着该字段只在反序列化(即从 JSON 转换为 Java 对象)时被读取,而在序列化(即从 Java 对象转换为 JSON)时不会被包含在输出中。

3️⃣关于mapper里面可以不使用注解还可以怎么查询数据库?

方法一:使用注解
@Select("SELECT t.*, d.device_mode, d.platform, c.case_name " +
            "FROM case_list_table t " +
            "JOIN device_detail_table d ON t.device_id = d.device_id " +
            "JOIN case_detail_table c ON t.case_id = c.case_id")
    @Results({
            @Result(column = "data_overview", property = "dataOverview", javaType = DataOverviewVO.class, jdbcType = JdbcType.VARCHAR, typeHandler = DataOverviewTypeHandler.class)
    })
方法二:使用 XML 映射文件
 <resultMap id="TaskVOMap" type="cn.ityao.cat.vo.TaskVO">
        <result column="data_overview" property="dataOverview" typeHandler="cn.ityao.cat.common.DataOverviewTypeHandler"/>
    </resultMap>

    <select id="selectAllTasks" resultMap="TaskVOMap">
        SELECT t.*, d.device_mode, d.platform, c.case_name
        FROM case_list_table t
                 JOIN device_detail_table d ON t.device_id = d.device_id
                 JOIN case_detail_table c ON t.case_id = c.case_id
    </select>
方法三:使用 MyBatis Plus 通用 Mapper 方法
	   继承通用接口,本查询继承了但感觉和前面两种方法差不多
		public interface TaskMapper extends BaseMapper<Task> {
		    List<TaskVO> selectAllTasks();
		}



追问:三种方法对查询效率有影响吗?三种方法的适配场景?

三种方法在查询效率上的影响通常可以忽略不计,因为它们最终都会生成相同的 SQL 语句并在数据库中执行。查询效率主要取决于 SQL 语句的优化和数据库的性能,而不是 MyBatis 的实现方式。
使用注解:
适用:简单的查询和小型项目。
优点:代码简洁,快速开发。
缺点:复杂查询时,代码可能变得冗长。

使用 XML 映射文件:
适用:复杂的查询和大型项目。
优点:集中管理 SQL 和映射关系,便于维护。
缺点:需要维护 XML 文件,对简单查询可能繁琐。

使用 MyBatis Plus 通用 Mapper 方法:
适用:需要快速开发和处理复杂查询的中大型项目。
优点:提供通用 CRUD 方法,结合 MyBatis 的灵活性和 MyBatis Plus 的便捷性。
缺点:需要学习 MyBatis Plus,复杂查询可能仍需 XML。

4️⃣三个表查询怎么提升查询效率?

如果经常需要根据多个字段进行查询,可以考虑创建复合索引(例如,CREATE INDEX idx_case_list_device_case ON case_list_table(device_id, case_id);),这可能比单独的索引更有效。
使用EXPLAIN命令来分析你的查询计划,看看这些索引是否被实际使用

5️⃣如何自定义URL(协议➕主机名➕端口号➕路径➕查询参数➕片段标识符)?

application.yml 中设置 server.address 和port 。一般是自己的IP和自定义的端口。
但是假如你设置为 192.168.1.100,那么服务器将尝试绑定到这个 IP 地址。如果这个 IP 地址在你的网络中不存在或者不可达,服务器将无法启动。

6️⃣如图启动时候显示的日志怎么自定义的?

在这里插入图片描述配置自己的banner

如果你没有在 application.yml 中配置banner,但启动时输出了 banner.txt 的内容,这通常是因为Spring Boot默认加载了类路径下的 banner.txt 文件。你可以通过配置文件或代码来禁用或自定义banner。

7️⃣http的丢包怎么控制的,数据量太大怎么办?

在处理HTTP请求时,特别是当数据量较大时,可能会遇到丢包问题。以下是一些控制丢包和处理大数据量的策略:
1. 使用分页(Pagination)
分页是一种常见的方法,用于处理大量数据。通过分页,可以将数据分成多个较小的部分,每次只返回一部分数据。

示例:

GET http://127.0.0.1:8080/api/list?page=1&size=10

Response:

{
  "status": 200,
  "message": "Success",
  "tasks": [
    // 返回第1页的10条记录
  ],
  "page": 1,
  "size": 10,
  "totalPages": 3,
  "totalElements": 25
}

2. 使用压缩(Compression)
启用HTTP压缩可以显著减少数据传输的大小。常见的压缩算法包括Gzip和Deflate。

示例:
在服务器端启用Gzip压缩:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CommonsRequestLoggingFilter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false).
                favorParameter(true).
                parameterName("format").
                defaultContentType(MediaType.APPLICATION_JSON).
                mediaType("xml", MediaType.APPLICATION_XML).
                mediaType("json", MediaType.APPLICATION_JSON);
    }

    @Bean
    public FilterRegistrationBean<GzipFilter> gzipFilter() {
        FilterRegistrationBean<GzipFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new GzipFilter());
        registrationBean.addUrlPatterns("/api/*");
        return registrationBean;
    }
}

3. 使用缓存(Caching)
通过缓存可以减少对数据库的重复查询,从而提高性能并减少数据传输。

示例:
在Spring Boot中启用缓存:

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableCaching
public class CacheConfig {
}

在服务方法上使用缓存注解:

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class TaskService {
    @Cacheable("tasks")
    public List<Task> getTasks() {
        // 查询数据库并返回任务列表
    }
}

4. 优化数据库查询
优化数据库查询可以减少数据传输量和提高查询效率。

示例:
使用索引、优化SQL查询、避免全表扫描等。

5. 使用WebSocket
对于实时数据传输,可以考虑使用WebSocket,它可以提供更稳定的双向通信。

示例:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MyWebSocketHandler(), "/websocket");
    }
}

*** 6. 监控和日志***
监控HTTP请求和响应,记录日志,以便及时发现和解决问题。

示例:
在Spring Boot中配置日志记录:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CommonsRequestLoggingFilter;

@Configuration
public class RequestLoggingFilterConfig {
    @Bean
    public CommonsRequestLoggingFilter logFilter() {
        CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
        filter.setIncludeQueryString(true);
        filter.setIncludePayload(true);
        filter.setMaxPayloadLength(10000);
        filter.setIncludeHeaders(false);
        filter.setAfterMessagePrefix("REQUEST DATA : ");
        return filter;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值