软件工程应用与实践(15)——请求与响应

2021SC@SDUSC

一、概述

在老年健康知识图谱系统中,后端与前端的交互是很重要的,在前端向后端发送请求的过程中,后端需要向前端返回响应的数据,而本篇博客将重点针对本项目中关于请求与响应的部分做相关分析。

经过小组讨论,决定由我分析关于响应和请求的部分,关于这块内容,在项目中的源码主要涉及一下几个部分

在前端中,有封装好的,发送请求的js文件,这些js文件中封装了一个个请求的函数,在前端vue页面中可以调用。

而在后端,则对请求包装了相应的相应对象,这些相应对象发送到前端之后,前端会根据不同的响应对象给出不同的处理。而在后端处理的过程中,可能会遇到一些异常情况,而老年健康知识图谱系统中,又对异常情况进行了相应的处理。

在下面的源码分析中,我会对这些部分做进一步分析。

二、源码分析

2.1 响应

为了更好地理解请求与响应的交互关系,我决定先阅读响应部分的源码,之后再理解请求部分的源码。

首先我们可以看到,在项目中,定义了三个文件夹,这三个文件夹分别描述了

  • 后端处理前端请求时可能遇到的异常
  • 后端处理异常
  • 返回给前端的具体的响应信息
    在这里插入图片描述
    1.响应信息

我们首先阅读响应信息部分的源码

首先我们可以看到,在对应的文件夹中,有一个BaseResponse类
在这里插入图片描述

在这个类中,描述了如下信息

  • 两个属性,相应的状态码和具体的信息
  • 有参构造,无参构造及相应的get和set方法
public class BaseResponse {

    private int statusCode = 200;
    private String message;

    public BaseResponse(int status, String message) {
        this.statusCode = status;
        this.message = message;
    }

    public BaseResponse() {
    }

    public String getMessage() {
        return message;
    }

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

    public int getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(int statusCode) {
        this.statusCode = statusCode;
    }
}

可以知道,这个类的主要作用是,用于描述正常执行时的响应状态。

接下来我们看到下一个类TableResultResponse,从类名上可以知道,这个类主要用于返回与表格相关的相应数据

  • 使用一个TableData对象存储表格数据
  • 在内部类TableData中,一个List类型的变量存储了表格每一行的数据,而另一个total变量则存储了表格的行数
public class TableResultResponse<T> extends BaseResponse {

    TableData<T> data;

    public TableResultResponse(long total, List<T> rows) {
        this.data = new TableData<T>(total, rows);
    }

    public TableResultResponse() {
        this.data = new TableData<T>();
    }

    TableResultResponse<T> total(int total) {
        this.data.setTotal(total);
        return this;
    }

    TableResultResponse<T> total(List<T> rows) {
        this.data.setRows(rows);
        return this;
    }

    public TableData<T> getData() {
        return data;
    }

    public void setData(TableData<T> data) {
        this.data = data;
    }

    class TableData<T> {
        long total;
        List<T> rows;

        public TableData(long total, List<T> rows) {
            this.total = total;
            this.rows = rows;
        }

        public TableData() {
        }

        public long getTotal() {
            return total;
        }

        public void setTotal(long total) {
            this.total = total;
        }

        public List<T> getRows() {
            return rows;
        }

        public void setRows(List<T> rows) {
            this.rows = rows;
        }
    }
}

本项目通过将表格数据的返回封装成一个对象,并在该类中使用了范型的技术,从而提高了利用效率,这是值得借鉴的。

接下来我们看到下一个类ObjectRestResponse,这个类主要用于返回对象类型的数据

  • 使用一个范型变量data存储对象的数据
  • 建立了相关的构造方法,get和set方法用于赋值
public class ObjectRestResponse<T> extends BaseResponse {

    T data;
    
    public ObjectRestResponse data(T data) {
        this.setData(data);
        return this;
    }
    public T getData() {
        return data;
    }

    public ObjectRestResponse setData(T data) {
        this.data = data;
        return this;
    }
}

本类与上面的类作用相似,只不过上面的类用于返回表格数据,而本类用于返回对象类型的数据

此外,这两个类都继承了上面的BaseResponse类,所以我们可以知道,对与BaseResponse类来说,他存在三种形式,第一种是原生的形式,第二种是返回表格数据的形式,第三种是返回对象类型数据的形式

接下来我们关注返回错误信息的类

关于错误信息的类,本项目中主要有两个

第一个是TokenForbiddenResponse类,同样继承了BaseResponse类,在这个类中,直接调用父类的构造方法,传入对应的状态码和消息。

public class TokenForbiddenResponse  extends BaseResponse {
    public TokenForbiddenResponse(String message) {
        super(RestCodeConstants.TOKEN_FORBIDDEN_CODE, message);
    }
}

第二个类与上面的类类似,同样返回了一个错误码

public class TokenErrorResponse extends BaseResponse {
    public TokenErrorResponse(String message) {
        super(RestCodeConstants.TOKEN_ERROR_CODE, message);
    }
}

而错误码在项目中同样有定义,定义为类中的静态变量,并且设置为常量,不可修改

public class RestCodeConstants {
    public static final int TOKEN_ERROR_CODE = 40101;
    public static final int TOKEN_FORBIDDEN_CODE = 40301;
}

2.异常类定义及处理

在本项目中,对后端可能发生的异常进行了相关的处理,经过小组讨论,将由我的另一个队友对异常处理部分做详尽的描述,这里我只对异常处理做简单的介绍。

本项目的异常处理与之前的上面的响应处理类似,都先定义了一个Basexxx作为基类,之后对该基类进行拓展,最终完善整个功能

在异常处理这一部分,本项目同样使用了一个基类,即BaseException,这个类首先继承了RuntimeException,并定义了相关的状态码,及set和get方法

public class BaseException extends RuntimeException {

    private int status = 200;

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public BaseException() {
    }

    public BaseException(String message,int status) {
        super(message);
        this.status = status;
    }

    public BaseException(String message) {
        super(message);
    }

    public BaseException(String message, Throwable cause) {
        super(message, cause);
    }

    public BaseException(Throwable cause) {
        super(cause);
    }

    public BaseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

而之后的其他类,也利用上面提到的,同样的方法继承了该Base异常类,从而达到对各个异常进行处理的作用

以下的代码就是具体的例子

public class UserInvalidException extends BaseException {
    public UserInvalidException(String message) {
        super(message, CommonConstants.EX_USER_PASS_INVALID_CODE);
    }
}
public class UserTokenException extends BaseException {
    public UserTokenException(String message) {
        super(message, CommonConstants.EX_USER_INVALID_CODE);
    }
}

关于本项目的异常处理,主要由下面的这个类完成,使用@ExceptionHandler注解,在括号中传入对应的异常类,用于指定处理对应异常类的方法。针对不同的异常,进行不同的处理。

@ControllerAdvice("com.sdu.nurse")
@ResponseBody
public class GlobalExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(ClientTokenException.class)
    public BaseResponse clientTokenExceptionHandler(HttpServletResponse response, ClientTokenException ex) {
        response.setStatus(403);
        logger.error(ex.getMessage(),ex);
        return new BaseResponse(ex.getStatus(), ex.getMessage());
    }

    @ExceptionHandler(UserTokenException.class)
    public BaseResponse userTokenExceptionHandler(HttpServletResponse response, UserTokenException ex) {
        response.setStatus(401);
        logger.error(ex.getMessage(),ex);
        return new BaseResponse(ex.getStatus(), ex.getMessage());
    }

    @ExceptionHandler(UserInvalidException.class)
    public BaseResponse userInvalidExceptionHandler(HttpServletResponse response, UserInvalidException ex) {
        response.setStatus(200);
        logger.error(ex.getMessage(),ex);
        return new BaseResponse(ex.getStatus(), ex.getMessage());
    }

    @ExceptionHandler(BaseException.class)
    public BaseResponse baseExceptionHandler(HttpServletResponse response, BaseException ex) {
        logger.error(ex.getMessage(),ex);
        response.setStatus(500);
        return new BaseResponse(ex.getStatus(), ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public BaseResponse otherExceptionHandler(HttpServletResponse response, Exception ex) {
        response.setStatus(500);
        logger.error(ex.getMessage(),ex);
        return new BaseResponse(CommonConstants.EX_OTHER_CODE, ex.getMessage());
    }
}

在本类中,还注入了日志对象,用这个日志对象输出对应的日志。

2.2 请求

在看完了响应的部分,接下来我们关注项目中关于“请求”的部分。

在本项目中,关于请求的部分比较简单,在之前的博客中我也略有提及,在这里详细说明一下

本项目中的请求封装在api包下的js文件中,以用户请求为例,代码如下,首先我们可以看到,js的开始部分,引入了axios的fetch,下面的四种请求,返回的都是一个fetch对象。

以get请求为例,传入一个query对象,直接调用fetch,指定对应对应的url,指定method,指定params(get请求所带的参数)。

而在post请求中,将要传递给后端接口的参数写在data中。

import fetch from '@/plugin/axios'

export function page (query) {
  return fetch({
    url: '/api/nurse/user/page',
    method: 'get',
    params: query
  })
}

export function addObj (obj) {
  return fetch({
    url: '/api/nurse/user',
    method: 'post',
    data: obj
  })
}

export function getObj (id) {
  return fetch({
    url: '/api/nurse/user/' + id,
    method: 'get'
  })
}

export function delObj (id) {
  return fetch({
    url: '/api/nurse/user/' + id,
    method: 'delete'
  })
}

export function putObj (id, obj) {
  return fetch({
    url: '/api/nurse/user/' + id,
    method: 'put',
    data: obj
  })
}

在具体的页面中,该项目中调用了上面封装好的请求代码,在按下确认按钮后,执行then方法,then方法中调用了delObj方法,而该方法封装在js代码中。

handleDelete (row) {
   this.$confirm('此操作将永久删除, 是否继续?', '提示', {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
   })
     .then(() => {
       delObj(row.id)
         .then(() => {
           this.$notify({
             title: '成功',
             message: '删除成功',
             type: 'success',
             duration: 2000
           })
           const index = this.list.indexOf(row)
           this.list.splice(index, 1)
         })
     })
 }

三、总结

在本次阅读源码的过程中,我主要分析了老年健康知识图谱系统中关于请求和响应的内容。在本次阅读源码的过程中,我体会到了该项目在请求封装和异常类封装的巧妙之处,在这个过程中也感谢老师和小组成员对我的帮助,本学期的软件工程应用与实践的源码分析就分析到这里,之后还有一篇博客用于总结。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
信息融合工程实践涉及到多个技术和方法,以下是一些常见的: 1. 数据采集和处理:信息融合的第一步是收集和处理各种数据源的信息。这可以包括从传感器、数据库、网络爬虫等收集数据,并对其进行清洗、过滤和转换,以便进一步处理和分析。 2. 数据集成和融合:在数据收集和处理之后,需要将来自不同数据源的信息进行集成和融合。这可能涉及到数据匹配、关联、转换等技术,以确保不同数据源的信息可以有效地结合在一起。 3. 数据挖掘和分析:信息融合的目标是从多个数据源中发现潜在的关联和模式。数据挖掘和分析技术,如聚类、分类、关联规则挖掘等,可以帮助揭示隐藏在数据中的有价值的信息。 4. 信息推理和推断:在信息融合中,有时需要根据已有的信息进行推理和推断。这可能涉及到知识表示和推理技术,如基于规则的推理、模糊逻辑、贝叶斯网络等,以便从已有的信息中推导出新的结论。 5. 可视化和交互:为了更好地理解和利用融合后的信息,可视化和交互技术变得至关重要。通过将信息以可视化的方式呈现,并提供交互功能,可以帮助用户更好地理解和分析融合后的信息。 以上只是一些常见的技术和方法,实际的信息融合工程实践可能涉及到更多领域的知识和技术。具体应用情境下,需要根据需求和约束来选择适合的技术和方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值