创建第一个服务,并对返回接口进行统一封装

100 阅读5分钟

上期我们完成了Spring boot 项目的搭建,本期我们实现一个简单的接口服务。

一 、创建接口服务

无论是Spring MVC还是Restful风格的接口服务,spring-boot-starter-web中都包含其注解@RestController@Controller

引入webjar.png

注意:由于 spring-boot-starter-web 默认替我们引入了核心启动器 spring-boot-starter,因此,当 Spring Boot 项目中的 pom.xml 引入了 spring-boot-starter-web 的依赖后,就无须在引入 spring-boot-starter 核心启动器的依赖了

  • 首先,在pom.xml文件中引入spring-boot-starter-web:
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 <version>2.7.6</version>
 <scope>compile</scope>
</dependency>
  • 创建DTO对象

创建接口传输对象UserDto,代码如下:

package com.holmium.springboot.app.dto;

/**
 * @author holmium
 * @description: 用户对象
 * @date 2023年04月15日
 */
public class UserDto {

    /**
     * 用户ID
     */
    String userId;

    /**
     * 用户名
     */
    String userName;
    /**
     * 性别
     */
    String sex;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}
  • 创建接口类UserApi

UserApi对外提供Restful风格的接口服务

package com.holmium.springboot.app.api;

import com.holmium.springboot.app.dto.UserDto;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author holmium
 * @description:
 * @date 2023年04月14日11:50
 */
@RestController
public class UserApi {

    @GetMapping(value = "/userinfo")
    public UserDto gerUserInfo() {
        UserDto user = new UserDto();
        user.setUserId("888888");
        user.setUserName("holmium");
        user.setSex("1");
        return user;
    }
}
  • 测试接口

启动接口服务,通过接口测试工具对接口进行访问,结果如下:

测试结果.png

二、返回统一格式结果优化

从上述接口返回结果可以看到,接口返回的数据使我们自己定义的对象,所以每个接口返回的结果格式都不尽相同,这样给接口使用者带来一定困扰,我们可不可以对定义一个统一格式的返回结果?答案是肯定。

  • 首先,我们创建统一返回结果对象Result类
package com.holmium.springboot.common.resp;

/**
 * @author holmium
 * @description 统一的返回结果
 * @date 2023年04月15日15:11
 */
public class Result<T>{
   /**
     * 请求响应代码,如:001-成功,000-失败
     */
    private String code;

    /**
     * 请求返回信息描述或异常信息
     */
    private String message;
    /**
     *接口请求返回业务对象数据
     */
    private T data;

    public Result() {
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
  • 第二步,我们对UserApi返回结果进行改造
package com.holmium.springboot.app.api;

import com.holmium.springboot.app.dto.UserDto;
import com.holmium.springboot.app.resp.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author holmium
 * @description:
 * @date 2023年04月15日23:50
 */
@RestController
public class UserApi {

    @GetMapping(value = "/userinfo")
    public Result<UserDto> gerUserInfo() {
        //接口返回数据对象
        UserDto user = new UserDto();
        user.setUserId("888888");
        user.setUserName("holmium");
        user.setSex("1");

        //接口统一返回结果
        Result<UserDto> result = new Result<>();
        result.setData(user);
        result.setCode("001");
        result.setMessage("接口调用成功");
        return result;
    }
}
  • 调整后返回结果如下:

统一返回结果.png

三、接口异常异常统一封装

实际业务开发中,在系统运行中常常会抛出各种异常,这些异常,如果不对异常进行封装的话, 异常将会注解抛给接口调用方,程序显得极不友好,并且对于有些我们没有预料到的异常,就会直接抛给用户。

  • 举例:未做任何处理的异常

    • 进行异常模拟改造

增加User处理的类,在类中增加方法getUser(),直接抛出异常:

package com.holmium.springboot.domain.user.impl;

import com.holmium.springboot.common.dto.UserDto;
import com.holmium.springboot.domain.user.User;
import org.springframework.stereotype.Service;

/**
 * @author holmium
 * @date 2023年04月16日 0:14
 */
@Service
public class UserImpl implements User {
    @Override
    public UserDto getUser() throws Exception {
        throw new Exception("接口调用异常");
    }
}
  • 在接口类中调用上述方法
package com.holmium.springboot.app.api;

import com.holmium.springboot.app.vo.UserVo;
import com.holmium.springboot.common.enums.CodeEnum;
import com.holmium.springboot.common.resp.Result;
import com.holmium.springboot.domain.user.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author holmium
 * @description:
 * @date 2023年04月15日23:50
 */
@RestController
public class UserApi {

   @Resource
    User user;


    @GetMapping(value = "/userinfo")
    public Result<UserVo> gerUserInfo(@RequestParam("id") Long id) {
        //接口统一返回结果
        Result<UserVo> result = new Result<>();
        if(id==1) {
          //TODO:
        }else{
            try {
                user.getUser();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return result;
    }
}
  • 测试服务
    从返回结果和后台服务日志来看测试结果

测试工具-接口异常结果.png

接口异常后台日志.png

图 测试结果 图后台日志

从测试结果发现,接口返回信息不准确,也极不友好,跟正常返回格式不同,对于接口调用方来说,增加了处理难度。

  • 对异常进行统一封装处理

对异常进行捕捉,增加统一返回结果封装。

package com.holmium.springboot.app.api;

import com.holmium.springboot.app.vo.UserVo;
import com.holmium.springboot.common.enums.CodeEnum;
import com.holmium.springboot.common.resp.Result;
import com.holmium.springboot.domain.user.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author holmium
 * @description:
 * @date 2023年04月15日23:50
 */
@RestController
public class UserApi {

   @Resource
    User user;


    @GetMapping(value = "/userinfo")
    public Result<UserVo> gerUserInfo(@RequestParam("id") Long id) {
        //接口统一返回结果
        Result<UserVo> result = new Result<>();
        if(id==1) {
            //TODO:
        }else{
            try {
                user.getUser();
            } catch (Exception e) {
                result.setCode(CodeEnum.FAIL.getCode());
                result.setMessage(e.getMessage());
            }
        }
        return result;
    }
}
  • 改造后测试

封装后异常测试结果.png

封装异常后后台.png

经过统一封装后,返回结果同正常请求结果返回格式相同,调用方调用接口更加友好更加友好

四、引入lombok,简化对象写法

在实际工作中,我们要写大量的各种对象,这些对象属性都有getset方法,手写起来非常麻烦,是否有什么方法可以简化对象的编写,不用写getset方法?引入lombok插件,即可解决这个问题

在pom文件中引入Lombok的jar包

 <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
 </dependency>

在对象类中添加@Data注解

在类上添加@Data注解后,不用在编写getset方法,在引用这个类对象的时候,可以直接调用getset方法,和之前一模一样,这大大简化的对象属性编写,尤其当对象属性比较多的时候,这种编写更加明显

@Data //增加@Data注解,简化get和set方法
public class UserVo {

    /**
     * 用户ID
     */
    String userId;

    /**
     * 用户名
     */
    String userName;
    /**
     * 性别:1-男 0-女
     */
    String sex;

}

五、写在最后

上述接口虽然进行统一结果返回封装,但是我们发现接口层添加了大量的代码,且每一个接口都有大量的冗余代码,能否对接口层进行进一步简化,对公共部门进行统一处理呢? 下期我们将对接口统一返回和异常统一返回进行封装。