Зачем унифицировать возвращаемые значения
Когда мы делаем серверные приложения, когда интерфейс и сервер разделены, мы часто определяем формат данных, который обычно включаетcode
,message
,data
Эти три важные информации для облегчения нашего общения, давайте посмотрим непосредственно на код
ReturnVO
package indi.viyoung.viboot.util;
import java.util.Properties;
/**
* 统一定义返回类
*
* @author yangwei
* @since 2018/12/20
*/
public class ReturnVO {
private static final Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + "/viboot-common/src/main/resources/response.properties");
/**
* 返回代码
*/
private String code;
/**
* 返回信息
*/
private String message;
/**
* 返回数据
*/
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
/**
* 默认构造,返回操作正确的返回代码和信息
*/
public ReturnVO() {
this.setCode(properties.getProperty(ReturnCode.SUCCESS.val()));
this.setMessage(properties.getProperty(ReturnCode.SUCCESS.msg()));
}
/**
* 构造一个返回特定代码的ReturnVO对象
* @param code
*/
public ReturnVO(ReturnCode code) {
this.setCode(properties.getProperty(code.val()));
this.setMessage(properties.getProperty(code.msg()));
}
/**
* 默认值返回,默认返回正确的code和message
* @param data
*/
public ReturnVO(Object data) {
this.setCode(properties.getProperty(ReturnCode.SUCCESS.val()));
this.setMessage(properties.getProperty(ReturnCode.SUCCESS.msg()));
this.setData(data);
}
/**
* 构造返回代码,以及自定义的错误信息
* @param code
* @param message
*/
public ReturnVO(ReturnCode code, String message) {
this.setCode(properties.getProperty(code.val()));
this.setMessage(message);
}
/**
* 构造自定义的code,message,以及data
* @param code
* @param message
* @param data
*/
public ReturnVO(ReturnCode code, String message, Object data) {
this.setCode(code.val());
this.setMessage(message);
this.setData(data);
}
@Override
public String toString() {
return "ReturnVO{" +
"code='" + code + '\'' +
", message='" + message + '\'' +
", data=" + data +
'}';
}
}
Здесь я предоставляю несколько конструкторов для использования в разных ситуациях. Комментарии к коду написаны очень четко, и все должны это четко видеть~
ReturnCode
Внимательные одноклассники может и узнали, я определил отдельныйReturnCode
Класс перечисления используется для хранения кода и возвращаемого сообщения:
package indi.viyoung.viboot.util;
/**
* @author yangwei
* @since 2018/12/20
*/
public enum ReturnCode {
/** 操作成功 */
SUCCESS("SUCCESS_CODE", "SUCCESS_MSG"),
/** 操作失败 */
FAIL("FAIL_CODE", "FAIL_MSG"),
/** 空指针异常 */
NullpointerException("NPE_CODE", "NPE_MSG"),
/** 自定义异常之返回值为空 */
NullResponseException("NRE_CODE", "NRE_MSG");
private ReturnCode(String value, String msg){
this.val = value;
this.msg = msg;
}
public String val() {
return val;
}
public String msg() {
return msg;
}
private String val;
private String msg;
}
Здесь я поместил данные для хранения не непосредственно в перечисление, а в файл конфигурации, что не только облегчает нам изменение соответствующей информации, но и облегчает ее чтение.
SUCCESS_CODE=2000
SUCCESS_MSG=操作成功
FAIL_CODE=5000
FAIL_MSG=操作失败
NPE_CODE=5001
NPE_MSG=空指针异常
NRE_CODE=5002
NRE_MSG=返回值为空
Обратите внимание, что имя атрибута и значение атрибута здесь соответствуют значению и msg в классе перечисления соответственно, так что мы можем легко прочитать поток ввода-вывода.
Здесь следует отметить, что если вы используете редактор IDEA, вам необходимо изменить следующую конфигурацию, чтобы при редактировании файла конфигурации вы писали китайский язык, но фактически сохраняли байт-код ASCII.
Далее, давайте взглянем на класс инструмента, который гласит:
package indi.viyoung.viboot.util;
import java.io.*;
import java.util.Iterator;
import java.util.Properties;
/**
* 读取*.properties中的属性
* @author vi
* @since 2018/12/24 7:33 PM
*/
public class ReadPropertiesUtil {
public static Properties getProperties(String propertiesPath){
Properties properties = new Properties();
try {
InputStream inputStream = new BufferedInputStream(new FileInputStream(propertiesPath));
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
return properties;
}
}
Здесь я написал статический метод напрямую, а входящим параметром является расположение файла свойств.В этом случае также объясняется исходный код этой статьи.
private static final Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + "/viboot-common/src/main/resources/response.properties");
Используйте ReturnVO
@RequestMapping("/test")
public ReturnVO test(){
try {
//省略
//省略
} catch (Exception e) {
e.printStackTrace();
}
return new ReturnVO();
}
Теперь мы можем получить доступ к этому интерфейсу и посмотреть, что мы получаем:
Но теперь проблема возникает снова, потому чтоtry...catch...
Существование кода всегда будет делать код очень повторяющимся.Нужно потратить минимум три-десять секунд, чтобы написать этот интерфейс для интерфейса.Если вы не знаете горячих клавиш редактора, это даже кошмар. Мы просто хотим полностью сосредоточиться на реализации бизнеса, а не тратить много времени на написание какого-то повторяющегося «просто необходимого» кода.
Глобальная обработка исключений с использованием АОП
(Здесь я просто даю краткое объяснение глобальной обработки исключений, которая будет подробно описана в следующем разделе)
/**
* 统一封装返回值和异常处理
*
* @author vi
* @since 2018/12/20 6:09 AM
*/
@Slf4j
@Aspect
@Order(5)
@Component
public class ResponseAop {
private static final Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + "/viboot-common/src/main/resources/response.properties");
/**
* 切点
*/
@Pointcut("execution(public * indi.viyoung.viboot.*.controller..*(..))")
public void httpResponse() {
}
/**
* 环切
*/
@Around("httpResponse()")
public ReturnVO handlerController(ProceedingJoinPoint proceedingJoinPoint) {
ReturnVO returnVO = new ReturnVO();
try {
//获取方法的执行结果
Object proceed = proceedingJoinPoint.proceed();
//如果方法的执行结果是ReturnVO,则将该对象直接返回
if (proceed instanceof ReturnVO) {
returnVO = (ReturnVO) proceed;
} else {
//否则,就要封装到ReturnVO的data中
returnVO.setData(proceed);
}
} catch (Throwable throwable) {
//如果出现了异常,调用异常处理方法将错误信息封装到ReturnVO中并返回
returnVO = handlerException(throwable);
}
return returnVO;
}
/**
* 异常处理
*/
private ReturnVO handlerException(Throwable throwable) {
ReturnVO returnVO = new ReturnVO();
//这里需要注意,返回枚举类中的枚举在写的时候应该和异常的名称相对应,以便动态的获取异常代码和异常信息
//获取异常名称的方法
String errorName = throwable.toString();
errorName = errorName.substring(errorName.lastIndexOf(".") + 1);
//直接获取properties文件中的内容
returnVO.setMessage(properties.getProperty(ReturnCode.valueOf(errorName).msg()));
returnVO.setCode(properties.getProperty(ReturnCode.valueOf(errorName).val()));
return returnVO;
}
}
Если нам нужно сделать это в каждом проекте, нам нужно поместить этот класс в общий модуль, а затем импортировать этот модуль в pom
<dependency>
<groupId>indi.viyoung.course</groupId>
<artifactId>viboot-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
Здесь следует обратить внимание на одну вещь: вы должны убедиться, что ваш pointcut написан правильно! ! В противном случае pointcut будет недействительным, и его нужно настроить в классе запуска:
@ComponentScan(value = "indi.viyoung.viboot.*")
импортировано точноcommon
Все файлы в пакете, чтобы убедиться, чтоResponseAop
Этот класс загружается в контейнер Spring.
Давайте проверим это, получив доступ к нашей модифицированной записиfindAll
интерфейс:
@RequestMapping("/findAll")
public Object findAll(){
return userService.list();
}
PS: здесь я унижаю возвращаемое значение какObjectДля того, чтобы внести данныеdata
, фактический тип должен бытьService
Тип возвращаемого интерфейса. Если нет возвращаемого значения, тоnew
ОдинReturnVO
Объекты можно назначать напрямую через конструктор. Что касается возвращаемого типаReturnVO
Суждение, код также сделал специальную обработку, не хранится вdata
, но возвращается напрямую.
Ниже мы изменим метод теста и позвольте ему выбрать исключение, что наше настраиваемое значение возвращаемого запроса пустое:
@RequestMapping("/test")
public ReturnVO test(){
throw new NullResponseException();
}
Затем давайте снова получим доступ к следующему тестовому интерфейсу:
Как видите, мы получаем желаемое сообщение, как указано в наших свойствах.
исходный код может идтиgithubилиОблако кодаСкачать, последующие примеры обновляются синхронно.
публика
Оригинал статьи, ограниченный стиль написания, недостаток знаний и знаний, если есть неточности в статье, сообщите пожалуйста.