当前位置:网站首页>Development specification: interface unified return value format [resend]
Development specification: interface unified return value format [resend]
2022-07-05 23:09:00 【Bug trendsetter】
boolean success ; The success of .
T data ; Specific return value upon success , On failure: null .
Integer code ; Return on success 0 , Return specific error code in case of failure .
String message ; Return on success null , Return specific error message on failure .
2.2 Define error code In order to be compatible with various types of error codes , It can be solved by declaring interfaces , The interface is implemented by the specific business error code class .① First, in the demo-common Layer of com.example.demo.common Add... To the package error Catalog and create new ServiceErrors Error code interface class .package com.example.demo.common.error;
public interface ServiceErrors {
/**
* Get error code
*
* @return Integer
*/
Integer getCode();
/**
* Get error messages
*
* @return String
*/
String getMessage();
}
② Secondly, define a business error code enumeration class to implement the above interface class . package com.example.demo.common.error;
public enum DemoErrors implements ServiceErrors {
/**
* Error code
*/
SYSTEM_ERROR(10000, " System error "),
PARAM_ERROR(10001, " Parameter error "),
;
private Integer code;
private String message;
DemoErrors(Integer code, String message) {
this.code = code;
this.message = message;
}
@Override
public Integer getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
2.3 Definition Result Return to the packaging class Continue to demo-common Layer of com.example.demo.common Add... To the package entity Catalog and create new Result Return to the packaging class . It provides wrapSuccessfulResult And wrapErrorResult Method is used to return when an interface call succeeds or fails . package com.example.demo.common.entity;
import com.example.demo.common.error.ServiceErrors;
import java.io.Serializable;
public class Result<T> implements Serializable {
private T data;
private boolean success;
private Integer code;
private String message;
public Result() {
}
public static <T> Result<T> wrapSuccessfulResult(T data) {
Result<T> result = new Result<T>();
result.data = data;
result.success = true;
result.code = 0;
return result;
}
public static <T> Result<T> wrapSuccessfulResult(String message, T data) {
Result<T> result = new Result<T>();
result.data = data;
result.success = true;
result.code = 0;
result.message = message;
return result;
}
public static <T> Result<T> wrapErrorResult(ServiceErrors error) {
Result<T> result = new Result<T>();
result.success = false;
result.code = error.getCode();
result.message = error.getMessage();
return result;
}
public static <T> Result<T> wrapErrorResult(ServiceErrors error, Object... extendMsg) {
Result<T> result = new Result<T>();
result.success = false;
result.code = error.getCode();
result.message = String.format(error.getMessage(), extendMsg);
return result;
}
public static <T> Result<T> wrapErrorResult(Integer code, String message) {
Result<T> result = new Result<T>();
result.success = false;
result.code = code;
result.message = message;
return result;
}
public T getData() {
return this.data;
}
public Result<T> setData(T data) {
this.data = data;
return this;
}
public boolean isSuccess() {
return this.success;
}
public Result<T> setSuccess(boolean success) {
this.success = success;
return this;
}
public Integer getCode() {
return this.code;
}
public Result<T> setCode(Integer code) {
this.code = code;
return this;
}
public String getMessage() {
return this.message;
}
public Result<T> setMessage(String message) {
this.message = message;
return this;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("success=");
sb.append(this.success);
sb.append(",");
sb.append("code=");
sb.append(this.code);
sb.append(",");
sb.append("message=");
sb.append(this.message);
sb.append(",");
sb.append("data=");
sb.append(this.data);
sb.append("}");
return sb.toString();
}
}
2.4 Define business exception classes stay demo-biz Layer of com.example.demo.biz Add... To the package exception Catalog and create new BizException Exception class . package com.example.demo.biz.exception;
import com.example.demo.common.error.ServiceErrors;
public class BizException extends RuntimeException {
private final Integer code;
public BizException(ServiceErrors errors) {
super(errors.getMessage());
this.code = errors.getCode();
}
public BizException(Integer code, String message) {
super(message);
this.code = code;
}
public Integer getCode() {
return this.code;
}
}
2.5 Define exception handling facets After the preparatory work is done , Then there's the real unified format processing . Whether it's HTTP Interface still RPC Interface , When dealing with business logic , By throwing business exceptions , Again by Spring AOP Tangent snap and encapsulate return value , So as to achieve the goal of unifying the return value format of the external interface .① First, in the demo-web Layer of pom Introduce in the file Spring AOP The dependency package of . The package has been integrated in Spring Boot In the parent project provided , Just introduce it here . <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
② Secondly, in demo-web Layer of com.example.demo.web Add... To the package aspect Catalog and create new DubboServiceAspect Section class . adopt 「 Interceptor 」 And 「 Reflection 」 The implementation encapsulates the business exception as Result return . package com.example.demo.web.aspect;
import com.example.demo.biz.exception.BizException;
import com.example.demo.common.entity.Result;
import com.example.demo.common.error.DemoErrors;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
@Slf4j
@Component
public class DubboServiceAspect implements MethodInterceptor {
@Override
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
try {
return methodInvocation.proceed();
} catch (BizException e) {
log.error("BizException", e);
return exceptionProcessor(methodInvocation, e);
} catch (Exception e) {
log.error("Exception:", e);
return exceptionProcessor(methodInvocation, e);
}
}
private Object exceptionProcessor(MethodInvocation methodInvocation, Exception e) {
Object[] args = methodInvocation.getArguments();
Method method = methodInvocation.getMethod();
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
log.error("dubbo service [method=" + methodName + "] params=" + Arrays.toString(args) + " abnormal :", e);
Class<?> clazz = method.getReturnType();
if (clazz.equals(Result.class)) {
Result result = new Result();
result.setSuccess(false);
if (e instanceof BizException) {
result.setCode(((BizException) e).getCode());
result.setMessage(e.getMessage());
} else {
result.setCode(DemoErrors.SYSTEM_ERROR.getCode());
result.setMessage(DemoErrors.SYSTEM_ERROR.getMessage());
}
return result;
}
return null;
}
}
③ Define the processing class and then pass Spring XML The formal definition of facets , stay demo-web Layer of resources Create a new spring-aop.xml file , Define in it Dubbo Section of the interface . <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:config>
<aop:pointcut id="dubboRemoteServiceAspect"
expression="execution(* com.example.demo.remote.service.*.*(..))"/>
<aop:advisor advice-ref="dubboServiceAspect" pointcut-ref="remoteServiceAspect"/>
</aop:config>
</beans>
④ Continue to demo-web Layer of resources Directory , New again application-context.xml Document management all Spring XML The configuration file , Now let's import spring-aop.xml file . <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:spring-aop.xml"/>
</beans>
⑤ Last in DemoWebApplication Pass through in the entry class @ImportResource Annotation import Spring Of XML The configuration file . @ImportResource({"classpath:application-context.xml"})
At this time, the aspect handling the exception has been configured , Next, we modify the definition of RpcDemoService.test Methods to test whether the section is effective . 2.6 Section test ① First of all, will RpcDemoService.test The return result of the method is Result packing . package com.example.demo.remote.service;
import com.example.demo.common.entity.Result;
import com.example.demo.remote.model.param.DemoParam;
import com.example.demo.remote.model.result.DemoDTO;
public interface RpcDemoService {
/**
* Dubbo The interface test
*
* @param param DemoParam
* @return DemoDTO
*/
Result<DemoDTO> test(DemoParam param);
}
package com.example.demo.biz.service.impl.remote;
import com.alibaba.dubbo.config.annotation.Service;
import com.example.demo.biz.service.DemoService;
import com.example.demo.common.entity.Result;
import com.example.demo.remote.model.param.DemoParam;
import com.example.demo.remote.model.result.DemoDTO;
import com.example.demo.remote.service.RpcDemoService;
import org.springframework.beans.factory.annotation.Autowired;
@Service
public class RpcDemoServiceImpl implements RpcDemoService {
@Autowired
private DemoService demoService;
@Override
public Result<DemoDTO> test(DemoParam param) {
DemoDTO demo = new DemoDTO();
demo.setStr(demoService.test(param.getId()));
return Result.wrapSuccessfulResult(demo);
}
}
② Revise DemoService.test The internal logic of the method , After querying the database, first judge whether there is data , If not, throw a business exception . package com.example.demo.biz.service.impl;
import com.example.demo.biz.exception.BizException;
import com.example.demo.biz.service.DemoService;
import com.example.demo.common.error.DemoErrors;
import com.example.demo.dao.entity.UserDO;
import com.example.demo.dao.mapper.business.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.util.Objects;
@Service
public class DemoServiceImpl implements DemoService {
@Autowired
private UserMapper userMapper;
@Override
public String test(Integer id) {
Assert.notNull(id, "id Can't be empty ");
UserDO user = userMapper.selectById(id);
if (Objects.isNull(user)) {
throw new BizException(DemoErrors.USER_IS_NOT_EXIST);
}
return user.toString();
}
}
③ then cd To demo-remote Catalog , perform mvn deploy Order repacking . At this point, the adjustment of the service provider is over , Next through the test project to see the effect .④ Come to the test project , In adjustment TestController.test Method , increase id The ginseng . package com.yibao.dawn.web.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.example.demo.common.entity.Result;
import com.example.demo.remote.model.param.DemoParam;
import com.example.demo.remote.model.result.DemoDTO;
import com.example.demo.remote.service.RpcDemoService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("test")
public class TestController {
@Reference(version = "1.0.0.dev")
private RpcDemoService rpcDemoService;
@GetMapping("dubbo")
public Result<DemoDTO> test(@RequestParam("id") Integer id) {
DemoParam param = new DemoParam();
param.setId(id);
return rpcDemoService.test(param);
}
}
⑤ The test is transmitting parameters id = 1 And id = 2 Under the circumstances , The results are as follows : 
package com.example.demo.web.aspect;
import com.example.demo.biz.exception.BizException;
import com.example.demo.common.entity.Result;
import com.example.demo.common.error.DemoErrors;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class HttpServiceAspect implements MethodInterceptor {
@Override
public Result invoke(final MethodInvocation methodInvocation) throws Throwable {
Result result = new Result();
try {
String methodName = methodInvocation.getMethod().getName();
if (log.isDebugEnabled()) {
log.debug("starting business logic processing.... " + methodName);
}
result = (Result) methodInvocation.proceed();
if (log.isDebugEnabled()) {
log.debug("finished business logic processing...." + methodName);
}
} catch (BizException e) {
result.setSuccess(false);
result.setCode(e.getCode());
result.setMessage(e.getMessage());
} catch (IllegalArgumentException e) {
result.setSuccess(false);
result.setCode(DemoErrors.PARAM_ERROR.getCode());
result.setMessage(e.getMessage());
} catch (RuntimeException e) {
log.error(" System error ", e);
result.setSuccess(false);
result.setCode(DemoErrors.SYSTEM_ERROR.getCode());
result.setMessage(DemoErrors.SYSTEM_ERROR.getMessage());
}
return result;
}
}
3.2 Define facets stay spring-aop.xml Add a section definition to the file . <aop:config>
<aop:pointcut id="resultControllerAspect"
expression="@within(org.springframework.web.bind.annotation.RestController)
and execution(com.example.demo.common.entity.Result *.*(..))"/>
<aop:advisor advice-ref="httpServiceAspect" pointcut-ref="resultControllerAspect"/>
</aop:config>
Four 、 Conclusion So far, the method of unified return value format of the interface is introduced , If there are more internal projects in the company , You can extract some common components as a project and make them into two-party packages for other projects to rely on , Keep the internal projects unified . notes : The relevant code has been synchronized to GitHub Symon Lin
https://symonlin.github.io/2019/03/18/specification-1
Share & Looking at
边栏推荐
- 一文搞定JVM的内存结构
- Leetcode buys and sells stocks
- ORB_ SLAM2/3
- Three. Js-01 getting started
- 2022 G3 boiler water treatment simulation examination and G3 boiler water treatment simulation examination question bank
- openresty ngx_lua正則錶達式
- VOT toolkit environment configuration and use
- First, redis summarizes the installation types
- SPSS analysis of employment problems of college graduates
- Global and Chinese markets of tantalum heat exchangers 2022-2028: Research Report on technology, participants, trends, market size and share
猜你喜欢
14种神笔记方法,只需选择1招,让你的学习和工作效率提高100倍!
2022.02.13 - SX10-30. Home raiding II
[speech processing] speech signal denoising and denoising based on MATLAB low-pass filter [including Matlab source code 1709]
东南亚电商指南,卖家如何布局东南亚市场?
Codeforces Global Round 19
One article deals with the microstructure and instructions of class
LabVIEW打开PNG 图像正常而 Photoshop打开得到全黑的图像
数据库基础知识(面试)
CorelDRAW plug-in -- GMS plug-in development -- new project -- macro recording -- VBA editing -- debugging skills -- CDR plug-in (2)
Registration and skills of hoisting machinery command examination in 2022
随机推荐
一文搞定JVM的内存结构
Openresty ngx Lua regular expression
查看网页最后修改时间方法以及原理简介
LabVIEW打开PNG 图像正常而 Photoshop打开得到全黑的图像
数据库基础知识(面试)
Global and Chinese market of networked refrigerators 2022-2028: Research Report on technology, participants, trends, market size and share
使用rewrite规则实现将所有到a域名的访问rewrite到b域名
The method and principle of viewing the last modification time of the web page
Roman numeral to integer
Simple and beautiful method of PPT color matching
2022 registration examination for safety management personnel of hazardous chemical business units and simulated reexamination examination for safety management personnel of hazardous chemical busines
Douban scoring applet Part-2
[speech processing] speech signal denoising and denoising based on MATLAB low-pass filter [including Matlab source code 1709]
Selenium+pytest automated test framework practice
判斷二叉樹是否為完全二叉樹
Week 17 homework
Judge whether the binary tree is a complete binary tree
The maximum happiness of the party
LeetCode145. Post order traversal of binary tree (three methods of recursion and iteration)
Nacos installation and service registration