代理网站备案,wordpress电视直播插件,外贸网站的作用,绵阳做网站的你好#xff0c;我是田哥 在这微服务架构盛行的黄金时段#xff0c;加上越来越多的前后端分离#xff0c;导致后端API接口规范变得越来越重要了。 比如#xff1a;统一返回参数形式、统一返回码、统一异常处理、集成swagger等。 目的主要是规范后端项目代码#xff0c;以及… 你好我是田哥 在这微服务架构盛行的黄金时段加上越来越多的前后端分离导致后端API接口规范变得越来越重要了。 比如统一返回参数形式、统一返回码、统一异常处理、集成swagger等。 目的主要是规范后端项目代码以及便于前端沟通联通以及问题的排查。 本文内容 统一返回参数形式 目前主流的返回参数形式 {code: 200000,message: 成功,data: {id: 1,userName: tiange,password: 123456,phone: 18257160375,gender: 0,status: 0,createTime: 2024-05-17 20:24:40}
} code是接口返回编码message是消息提示data是具体返回数据内容。 返回码 返回码定义很重要我们应该可以参考HTTP请求返回的状态码下面是常见的HTTP状态码 200 - 请求成功
301 - 资源网页等被永久转移到其它URL
404 - 请求的资源网页等不存在
500 - 内部服务器错误 这样前端开发人员在得到返回值后根据状态码就可以知道大概什么错误再根据message相关的信息描述可以快速定位。 由于我们业务系统中可能会又大量的code所以我们对此做一个改良。 /*** {code description:} 返回码** author tianwc 公众号Java后端技术全栈* 在线刷题 1200java面试题和1000篇技术文章a hrefhttps://woaijava.cc/博客地址/a* {code date:} 2024-07-28 15:10* {code version:} 1.0*/
Getter
public enum ResultCode implements Serializable {SUCCESS(200000, 成功),FAIL(500000, 系统错误请稍后重试!),USER_NOT_EXIST(401000, 用户不存在),USER_CANCELLED(401001, 用户已注销),USER_ROLE_ERROR(401002, 用户角色不对),NOT_FOUND(404000, 接口不存在),PARAMETER_ERROR(404001, 参数有误),PARAMETER_IS_NULL(404002, 参数为空);private final int code;private final String message;ResultCode(int code, String message) {this.code code;this.message message;}
} 对此我们还可以进一步细分比如402开头的是用户相关的 、403开头又是xxx的..... 这样后期如果又什么问题这样就能快速定位到具体模块中。 统一返回 我们可以专门写一个类来对返回数据进行包装。 /*** {code description:} 返回结果马甲** author tianwc 公众号Java后端技术全栈* 在线刷题 1200java面试题和1000篇技术文章a hrefhttps://woaijava.cc/博客地址/a* {code date:} 2024-07-28 15:12* {code version:} 1.0*/
Data
public class Result implements Serializable {private Integer code;private String message;private Object data;public Result(Integer code, String message, Object data) {this.code code;this.message message;this.data data;}public static Result success() {return new Result(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), null);}public static Result success(Object data) {return new Result(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);}public static Result fail(ResultCode resultCode) {return new Result(resultCode.getCode(), resultCode.getMessage(), null);}public static Result fail(int code, String message) {return new Result(code, message, null);}
} 我们定义了常用的四种格式。 具体使用如下 我们在Service层和实现层 public interface UserInfoService extends IServiceUserInfo {Result findByCondition(UserInfoReqDto userInfoReqDto);
} Service
public class UserInfoServiceImpl extends ServiceImplUserInfoMapper, UserInfo implements UserInfoService {Overridepublic Result findByCondition(UserInfoReqDto userInfoReqDto) {WrapperUserInfo wrapper Wrappers.UserInfolambdaQuery().eq(UserInfo::getUserName, userInfoReqDto.getUserName()).eq(UserInfo::getPassword, userInfoReqDto.getPassword());return Result.success(this.baseMapper.selectList(wrapper));}
} 在controller层我们会在controller层处理业务请求并返回给前端 。 RestController
RequestMapping(/user/info)
public class UserInfoController {Resourceprivate UserInfoService userInfoService; GetMapping(/condition)public Result findByCondition(UserInfoReqDto userInfoReqDto) {return userInfoService.findByCondition(userInfoReqDto);}
} 执行 GET http://localhost:8089/user/info/condition?userNametiangepassword123456 返回 {code: 200000,message: 成功,data: [{id: 1,userName: tiange,password: 123456,phone: 18257160375,gender: 0,status: 0,createTime: 2024-05-17T20:24:40.00000:00}]
} 前端根据我们但会的code判断是否需要取data字段。 统一异常处理 统一异常处理我们分业务异常、系统异常以及参数异常 业务异常 我们自定义一个业务异常BusinessException /*** author tianwc 公众号java后端技术全栈、面试专栏* version 1.0.0* date 2024-07-28 15:12* 在线刷题 1200java面试题和1000篇技术文章a hrefhttps://woaijava.cc/博客地址/a* p* 自定义业务异常*/
Getter
public class BusinessException extends RuntimeException {/*** http状态码*/private Integer code;private Object object;public BusinessException(String message, Integer code, Object object) {super(message);this.code code;this.object object;}public BusinessException(String message, Integer code) {super(message);this.code code;}public BusinessException(ResultCode resultCode) {super(resultCode.getMessage());this.code resultCode.getCode();this.object resultCode.getMessage();}public BusinessException(ResultCode resultCode, String message) {this.code resultCode.getCode();this.object message;}public BusinessException(String message) {super(message);}} 异常处理GlobalAdvice RestControllerAdvice
Slf4j
public class GlobalAdvice {ExceptionHandler(Exception.class)public Result doException(Exception e) {log.error(统一异常处理机制触发异常 msg , e);String message null;int errorCode ResultCode.FAIL.getCode();//自定义异常if (e instanceof BusinessException) {BusinessException exception (BusinessException) e;message exception.getMessage();errorCode exception.getCode();} else if (e instanceof HttpRequestMethodNotSupportedException) {message 不支持GET/POST方法;} else if (e instanceof NoHandlerFoundException) {message 请求接口不存在;} else if (e instanceof MissingServletRequestParameterException) {errorCode ResultCode.PARAMETER_IS_NULL.getCode();message String.format(缺少必要参数[%s], ((MissingServletRequestParameterException) e).getParameterName());} else if (e instanceof MethodArgumentNotValidException) {BindingResult result ((MethodArgumentNotValidException) e).getBindingResult();FieldError error result.getFieldError();errorCode ResultCode.PARAMETER_IS_NULL.getCode();message error null ? ResultCode.PARAMETER_ERROR.getMessage() : error.getDefaultMessage();} else if (e instanceof BindException) {errorCode ResultCode.PARAMETER_IS_NULL.getCode();message ((BindException) e).getFieldError().getDefaultMessage();} else if (e instanceof IllegalArgumentException) {errorCode ResultCode.PARAMETER_IS_NULL.getCode();message e.getMessage();}return Result.fail(errorCode, message);}
} 使用 Service
public class UserInfoServiceImpl extends ServiceImplUserInfoMapper, UserInfo implements UserInfoService {Overridepublic Result findByCondition(UserInfoReqDto userInfoReqDto) {if(admin.equals(userInfoReqDto.getUserName())){//对于某些业务问题抛出自定义异常throw new BusinessException(ResultCode.USER_ROLE_ERROR);}WrapperUserInfo wrapper Wrappers.UserInfolambdaQuery().eq(UserInfo::getUserName, userInfoReqDto.getUserName()).eq(UserInfo::getPassword, userInfoReqDto.getPassword());return Result.success(this.baseMapper.selectList(wrapper));}
} 系统异常 假设系统异常 Service
public class UserInfoServiceImpl extends ServiceImplUserInfoMapper, UserInfo implements UserInfoService {Overridepublic Result findByCondition(UserInfoReqDto userInfoReqDto) {if(123456.equals(userInfoReqDto.getPassword())){throw new RuntimeException(你的系统异常了);}WrapperUserInfo wrapper Wrappers.UserInfolambdaQuery().eq(UserInfo::getUserName, userInfoReqDto.getUserName()).eq(UserInfo::getPassword, userInfoReqDto.getPassword());return Result.success(this.baseMapper.selectList(wrapper));}
} 执行 GET http://localhost:8089/user/info/condition?userNametianpassword123456 返回结果 {code: 500000,message: 系统异常,data: null
} 参数校验 添加pom依赖 !--参数验证--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-validation/artifactId
/dependency 请求参数 Data
AllArgsConstructor
NoArgsConstructor
public class UserInfoReqDto {NotBlank(message 姓名不能为空)private String userName;NotBlank(message 密码不能为空)private String password;
} 其他相关注解 注解作用NotNull判断包装类是否为nullNotBlank判断字符串是否为null或者是空串(去掉首尾空格)NotEmpty判断集合是否为空Length判断字符的长度(最大或者最小)Min判断数值最小值Max判断数值最大值Email判断邮箱是否合法 controller层添加注解Validated RestController
RequestMapping(/user/info)
public class UserInfoController {Resourceprivate UserInfoService userInfoService; GetMapping(/condition)public Result findByCondition(Validated UserInfoReqDto userInfoReqDto) {return userInfoService.findByCondition(userInfoReqDto);}
} 最后在统一异常处理里处理。 执行 GET http://localhost:8089/user/info/condition?userNametian 返回 {code: 404002,message: 密码不能为空,data: null
} 执行 GET http://localhost:8089/user/info/condition?password123456 返回 {code: 404002,message: 姓名不能为空,data: null
} 集成mybatis-plus 添加依赖 !--mybatis-plus 依赖--
dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion${mybatis-plus.version}/version
/dependency
!--mysql依赖--
dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdscoperuntime/scope
/dependency 数据库信息配置 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver
spring.datasource.jdbc-urljdbc:mysql://localhost:3306/user-center?useSSLfalseserverTimezoneUTCuseUnicodetruecharacterEncodingutf-8allowPublicKeyRetrievaltrue
spring.datasource.usernameroot
spring.datasource.password123456 mybatis-plus配置 Configuration
MapperScan(basePackages com.tian.dao.mapper)
public class DataSourceConfig {ConfigurationProperties(prefix spring.datasource)Beanpublic DataSource dataSource() {return DataSourceBuilder.create().build();}Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor new MybatisPlusInterceptor();//分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor());//注册乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource, MybatisPlusInterceptor interceptor) throws Exception {MybatisSqlSessionFactoryBean ssfb new MybatisSqlSessionFactoryBean();ssfb.setDataSource(dataSource);ssfb.setPlugins(interceptor);//到哪里找xml文件ssfb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(classpath*:mapper/*.xml));return ssfb.getObject();}
} 实体类 TableName(value user_info)
Data
public class UserInfo {/*** 主键ID*/TableId(value id)private Long id;/*** 姓名*/TableField(value user_name)private String userName;/*** 密码*/TableField(value password)private String password;/*** 手机号*/TableField(value phone)private String phone;/*** 性别0女1男*/TableField(value gender)private Integer gender;/*** 状态0正常1已注销*/TableField(value status)private Integer status;/*** 注册时间*/TableField(value create_time)private Date createTime;TableField(exist false)private static final long serialVersionUID 1L;
} mapper public interface UserInfoMapper extends BaseMapperUserInfo {
} service部分代码参照前面的代码来。 执行 GET http://localhost:8089/user/info/condition?userNametiangepassword123456 返回 {code: 200000,message: 成功,data: [{id: 1,userName: tiange,password: 123456,phone: 18257160375,gender: 0,status: 0,createTime: 2024-05-17T20:24:40.00000:00}]
} 到这里我们的项目就成功把mybatis-plus集成进来。 swagger 作为前后端分离项目在团队开发中一个好的 API 文档不但可以减少大量的沟通成本还可以帮助一位新人快速上手业务。传统的做法是由开发人员创建一份 RESTful API文档来记录所有的接口细节并在程序员之间代代相传。这种做法存在以下几个问题 1API 接口众多细节复杂需要考虑不同的HTTP请求类型、HTTP头部信息、HTTP请求内容等想要高质量的完成这份文档需要耗费大量的精力 2难以维护。随着需求的变更和项目的优化、推进接口的细节在不断地演变接口描述文档也需要同步修订可是文档和代码处于两个不同的媒介除非有严格的管理机制否则很容易出现文档、接口不一致的情况 Swagger2 的出现就是为了从根本上解决上述问题。它作为一个规范和完整的框架可以用于生成、描述、调用和可视化 RESTful 风格的 Web 服务 接口文档在线自动生成文档随接口变动实时更新节省维护成本支持在线接口测试不依赖第三方工具 Swagger2 是一个规范和完整的框架用于生成、描述、调用和可视化Restful风格的web服务现在我们使用spring boot 整合它。作用 接口的文档在线自动生成功能测试 常用注解 注解描述Api将类标记为 Swagger 资源。ApiImplicitParam表示 API 操作中的单个参数。ApiImplicitParams允许多个 ApiImplicitParam 对象列表的包装器。ApiModel提供有关 Swagger 模型的其他信息。ApiModelProperty添加和操作模型属性的数据。ApiOperation描述针对特定路径的操作或通常是 HTTP 方法。ApiParam为操作参数添加额外的元数据。ApiResponse描述操作的可能响应。ApiResponses允许多个 ApiResponse 对象列表的包装器。Authorization声明要在资源或操作上使用的授权方案。AuthorizationScope描述 OAuth2 授权范围。 swagger配置 Configuration //加入到容器里面
EnableSwagger2 //开启Swagger
public class SwaggerConfig {Beanpublic Docket docket() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage(com.tian.controller)).build();}private ApiInfo apiInfo(){Contact contact new Contact(web项目demo, https://www.woaijava.cc/, 251965157qq.com);return new ApiInfo(web项目demo的API文档,练手所用,v1.0,https://www.woaijava.cc/,contact,Apache 2.0,http://www.apache.org/licenses/LICENSE-2.0,new ArrayList());}} 我们就可以在对应业务代码中标注上swagger RestController
RequestMapping(/user/info)
Api(value 用户信息接口,tags 用户信息)
public class UserInfoController {Resourceprivate UserInfoService userInfoService;GetMapping(/{id})ApiOperation(value 根据id查询用户信息, notes 根据id查询用户信息,produces application/json,consumes application/json)ApiImplicitParams({ApiImplicitParam(nameid,value用户id,required true,dataType Integer)})public Result findById(PathVariable(id) Integer id) {return Result.success(userInfoService.getById(id));}GetMapping(/condition)ApiOperation(value 根据条件查询用户信息)public Result findByCondition(Validated UserInfoReqDto userInfoReqDto) {return userInfoService.findByCondition(userInfoReqDto);}
} Data
AllArgsConstructor
NoArgsConstructor
ApiModel(value用户信息查询条件)
public class UserInfoReqDto {NotBlank(message 姓名不能为空)ApiModelProperty(value姓名)private String userName;NotBlank(message 密码不能为空)ApiModelProperty(value密码)private String password;
} 效果 启动项目访问 http://localhost:8089/swagger-ui.html 也到这里我们就基本形成了一个完整的demo级后端项目。 代码已上传到知识星球 其他推荐 2024年最新面试总结请查收 充电桩项目如何部署 应届生不会写简历手把手教你怎么写简历 背八股文不妨尝试这招