当前位置:网站首页>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
边栏推荐
- [speech processing] speech signal denoising and denoising based on MATLAB low-pass filter [including Matlab source code 1709]
- Element positioning of Web Automation
- Methods modified by static
- Using LNMP to build WordPress sites
- TypeError: this. getOptions is not a function
- The maximum happiness of the party
- regular expression
- 傅里叶分析概述
- Arduino measures AC current
- 一文搞定class的微觀結構和指令
猜你喜欢
Hainan Nuanshen tea recruits warmhearted people: recruitment of the product experience recommender of Nuanshen multi bubble honey orchid single cluster
Codeforces Global Round 19
Negative sampling
February 13, 2022-4-symmetric binary tree
CJ mccullem autograph: to dear Portland
Non rigid / flexible point cloud ICP registration
Sum of two numbers, sum of three numbers (sort + double pointer)
LabVIEW打开PNG 图像正常而 Photoshop打开得到全黑的图像
Common model making instructions
【Note17】PECI(Platform Environment Control Interface)
随机推荐
查看网页最后修改时间方法以及原理简介
Hcip day 11 (BGP agreement)
The difference between MVVM and MVC
Overview of Fourier analysis
Déterminer si un arbre binaire est un arbre binaire complet
实现反向代理客户端IP透传
Krypton Factor-紫书第七章暴力求解
First, redis summarizes the installation types
Codeforces Global Round 19
第十七周作业
Boring boring
Debian 10 installation configuration
3 find the greatest common divisor and the least common multiple
Douban scoring applet Part-2
Matlab smooth curve connection scatter diagram
2.13 summary
The maximum happiness of the party
二叉树递归套路总结
Alibaba Tianchi SQL training camp task4 learning notes
2022 registration examination for safety management personnel of hazardous chemical business units and simulated reexamination examination for safety management personnel of hazardous chemical busines