一个完整的后端请求包括什么?

  1. 接口地址(URL地址)。
  2. 请求方式(GET、POST、DELETE、PUT)
  3. 请求数据(request、head、body)
  4. 响应数据(response)

一、Controller层参数接收

@RestController
@RequestMapping("/product/product-info")
public class ProductInfoController {@AutowiredProductInfoService productInfoService;@GetMapping("/findById")public ProductInfoQueryVo findById(Integer id) {...}@PostMapping("/page")public IPage findPage(Page page, ProductInfoQueryVo vo) {// 传入的参数为一个实体类。// 只要前端传来的JSON能通过属性映射到实体类的属性就可以。...}
}
  1. @RestController:@RestController = @Controller + ResponseBody。加上这个注解,springboot就会吧这个类当成controller进行处理,然后把所有返回的参数放到ResponseBody中.。
  2. @RequestMapping:请求的前缀,也就是所有该Controller下的请求都需要加上/product/product-info的前缀。
  3. @GetMapping(“/findById”):标志这是一个get请求,并且需要通过/findById地址才可以访问到。
  4. @PostMapping(“/page”):表示是个post请求。
  5. 参数:至于参数部分,只需要写上ProductInfoQueryVo,前端过来的json请求便会通过映射赋值到对应的对象中,例如请求这么写,productId就会自动被映射到vo对应的属性当中。

二、统一实体类

为了防止不同的请求所造成的返回的数据不同,而造成前端的接收比较麻烦,后端要和前端进行统一类。

一般包括 状态码 1/0;

传递的信息message(“xxx操作是否成功”);

以及数据Object data;

package com.chang.common;import lombok.Data;
import java.util.HashMap;
import java.util.Map;/*通用返回结果类,服务端响应的数据会被封装成为此对象。此类是一个通用结果类,服务端响应的所有结果最终都会包装成此种类型返回给前端页面。加上泛型。*/
@Data
public class R<T> {private Integer code; //编码:1成功,0和其它数字为失败private String msg; //错误信息private T data; //数据private Map map = new HashMap(); //动态数据public static <T> R<T> success(T object) {R<T> r = new R<T>();r.data = object; // 对应一些员工数据什么的。r.code = 1;return r;}public static <T> R<T> error(String msg) {R r = new R();r.msg = msg;r.code = 0;return r;}/*** 操作map的动态数据* @param key* @param value* @return*/public R<T> add(String key, Object value) {this.map.put(key, value);return this;}
}

数据的封装的变化:

{"productId": 1,"productName": "泡脚","productPrice": 100.00,"productDescription": "中药泡脚加按摩","productStatus": 0,
}

经过封装后就变成了

{"code": 1000,"msg": "请求成功","data": {"productId": 1,"productName": "泡脚","productPrice": 100.00,"productDescription": "中药泡脚加按摩","productStatus": 0,}
}

然后前后端分离交互的 后端的Controller的返回值就需要统一一下了。

R<Xxx>

    @PostMapping("/findByVo")public ResultVo findByVo(@Validated ProductInfoVo vo) {ProductInfo productInfo = new ProductInfo();BeanUtils.copyProperties(vo, productInfo);return new ResultVo(productInfoService.getOne(new QueryWrapper(productInfo)));}
  • 一般情况下,查询Get操作的返回值为R<List> 或者R
  • return new R.success(list);
  • 删除、修改、增加的操作为R
  • return new R.success(“Xxx操作成功/失败!”);

当然也可通过枚举类来进行状态码的统一约定。因为是枚举类,会有get方法,而不会有set方法。

@Getter
public enum ResultCode implements StatusCode{SUCCESS(1000, "请求成功"),FAILED(1001, "请求失败"),VALIDATE_ERROR(1002, "参数校验失败"),RESPONSE_PACK_ERROR(1003, "response返回包装失败");private int code;private String msg;ResultCode(int code, String msg) {this.code = code;this.msg = msg;}
}

三、参数校验

在SpringBoot中,使用@Validate注解进行校验。

首先添加Maven依赖。

<dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId>
</dependency>

然后就可以在实体类字段的属性上面使用了。

message:当不符合校验条件的时候,IDEA会报告给我们什么信息。

String类型的判断用@NotBlank, 可防止空字符串。

@Data
public class ProductInfoVo {@NotNull(message = "商品名称不允许为空")private String productName;@Min(value = 0, message = "商品价格不允许为负数") //设置最小值private BigDecimal productPrice;private Integer productStatus;
}

测试:

1.写Controller层方法。

    @PostMapping("/findByVo")public ProductInfo findByVo(@Validated ProductInfoVo vo) {ProductInfo productInfo = new ProductInfo();BeanUtils.copyProperties(vo, productInfo);return new ResultVo(productInfoService.getOne(new QueryWrapper(productInfo)));}

2.传递数据。

productName : 泡脚
productPrice : -1
productStatus : 1

3.观看控制台的输出。

{"timestamp": "2020-04-19T03:06:37.268+0000","status": 400,"error": "Bad Request","errors": [{"codes": ["Min.productInfoVo.productPrice","Min.productPrice","Min.java.math.BigDecimal","Min"],"arguments": [{"codes": ["productInfoVo.productPrice","productPrice"],"defaultMessage": "productPrice","code": "productPrice"},0],"defaultMessage": "商品价格不允许为负数","objectName": "productInfoVo","field": "productPrice","rejectedValue": -1,"bindingFailure": false,"code": "Min"}],"message": "Validation failed for object\u003d\u0027productInfoVo\u0027. Error count: 1","trace": "org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors\nField error in object \u0027productInfoVo\u0027 on field \u0027productPrice\u0027: rejected value [-1]; codes [Min.productInfoVo.productPrice,Min.productPrice,Min.java.math.BigDecimal,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [productInfoVo.productPrice,productPrice]; arguments []; default message [productPrice],0]; default message [商品价格不允许为负数]\n\tat xxxxx"path": "/leilema/product/product-info/findByVo"
}

4.优化异常处理。

我们看到代码抛出了org.springframework.validation.BindException的绑定异常,因此我们的思路就是AOP拦截所有controller,然后异常的时候统一拦截起来,进行封装!完美!

为了响应上面我们定义的状态码,我们可以使用SpringMVC的注解@ExceptionHandler

Spring mvc给我们提供了一个@RestControllerAdvice来增强所有@RestController,然后使用@ExceptionHandler注解,就可以拦截到对应的异常。

@RestControllerAdvice(basePackages = {"com.bugpool.leilema"})
public class ControllerResponseAdvice implements ResponseBodyAdvice<Object> {@Overridepublic boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {// response是ResultVo类型,或者注释了NotControllerResponseAdvice都不进行包装return !methodParameter.getParameterType().isAssignableFrom(ResultVo.class);}@Overridepublic Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request, ServerHttpResponse response) {// String类型不能直接包装if (returnType.getGenericParameterType().equals(String.class)) {ObjectMapper objectMapper = new ObjectMapper();try {// 将数据包装在ResultVo里后转换为json串进行返回return objectMapper.writeValueAsString(new ResultVo(data));} catch (JsonProcessingException e) {throw new APIException(ResultCode.RESPONSE_PACK_ERROR, e.getMessage());}}// 否则直接包装成ResultVo返回return new ResultVo(data);}
}
  1. @RestControllerAdvice(basePackages = {“com.bugpool.leilema”})自动扫描了所有指定包下的controller,在Response时进行统一处理
  2. 重写supports方法,也就是说,当返回类型已经是ResultVo了,那就不需要封装了,当不等与ResultVo时才进行调用beforeBodyWrite方法,跟过滤器的效果是一样的
  3. 最后重写我们的封装方法beforeBodyWrite,注意除了String的返回值有点特殊,无法直接封装成json,我们需要进行特殊处理,其他的直接new ResultVo(data);就ok了

当然也有其他例子。

package com.chang.common;import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;import java.sql.SQLIntegrityConstraintViolationException;/*** 全局异常处理,对于指定的Controller的请求都要进行异常捕获and处理。*/
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {/*** 异常处理方法: 处理这种异常* @return*/@ExceptionHandler(SQLIntegrityConstraintViolationException.class)public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){log.error(ex.getMessage());if(ex.getMessage().contains("Duplicate entry")){String[] split = ex.getMessage().split(" ");// 这里是根据爆出的异常信息来进行分配的。String msg = split[2] + "已存在";return R.error(msg);}return R.error("未知错误");}/*** 异常处理方法: 处理这种异常* @return*/@ExceptionHandler(CustomException.class)public R<String> exceptionHandler(CustomException ex){log.error(ex.getMessage());return R.error(ex.getMessage());}
}

Controller层的处理相关推荐

  1. java domain层_java框架中的controller层、dao层、domain层、service层、view层

    1.Controller层:接口层,用户访问请求时对接. Controller层负责具体的业务模块流程的控制,在此层里面要调用Serice层的接口来控制业务流程,控制的配置也同样是在Spring的配置 ...

  2. Controller 层实现

    一.实验介绍 1.1 实验内容 本节课程主要利用 Spring MVC 框架实现 Controller 层以及一些辅助类的实现. 1.2 实验知识点 Spring MVC 框架 1.3 实验环境 JD ...

  3. Spring - @ControllerAdvice + @ExceptionHandler全局处理Controller层异常(转)

    Spring - @ControllerAdvice + @ExceptionHandler全局处理Controller层异常(转) 参考文章: (1)Spring - @ControllerAdvi ...

  4. java 框架 Dao层 Mapper层 controller层 service层 model层 entity层 简介

    目录 简介 entity层 mapper层 service层 controller层 简介 SSM是sping+springMVC+mybatis集成的框架. MVC即model view contr ...

  5. Spring中Controller层、Filter层、Interceptor层全局统一异常处理

    Controller层.Filter层.Interceptor层全局统一异常处理 SpringBoot为异常处理提供了很多优秀的方法,但是像我这种新手在处理异常时还是会觉得一头包,终于我痛定思痛,总结 ...

  6. springmvc+mybatis,在mybatis逆向工程的基础上使用模板自动生成controller层代码

    在使用mybatis和srpingmvc的过程中,有一点关注了很久,就是controller层 的代码无法自动生成,于是自己研究写了个小程序,可以通过数据库表.自己定制的controller文件的模板 ...

  7. 实战SSM_O2O商铺_41【前端展示】店铺列表页面Dao+Service+Controller层的实现

    文章目录 概述 Dao层 接口 映射文件 单元测试 Service层 接口方法 单元测试 Controller层 增加 ShopListController 单元测试 Github地址 概述 在完成了 ...

  8. 实战SSM_O2O商铺_39【前端展示】首页轮播图和一级商铺Dao+Service+Controller层的实现

    文章目录 概述 HeadLine Dao层 接口 映射文件 单元测试 HeadLine Service层 接口 实现类 单元测试 ShopCategory Dao层完善 映射文件完善 单元测试 Con ...

  9. 实战SSM_O2O商铺_36【商品】商品列表之Dao+Service+Controller层的实现

    文章目录 概述 Dao层 ProductDao.java ProductDao.xml 单元测试 Service层 ProductService.java ProductServiceImpl.jav ...

  10. 实战SSM_O2O商铺_34【商品】商品编辑之Controller层的实现

    文章目录 概述 ProductController 单元测试 Github地址 概述 在完成了 实战SSM_O2O商铺_33[商品]商品编辑之Service层的实现之后,我们继续来实现Controll ...

最新文章

  1. Networkx-cycle
  2. myeclipse2014 mysql连接池_myeclips配置mysql连接池
  3. python怎么下载-下载 python
  4. opencv 使用cvload加载xml出现错误原因解析及方法
  5. IT Monitor
  6. 未来大数据的处理和发展的五个趋势
  7. 关于字符集--总结,补遗以及问题
  8. JVM内存管理------GC算法精解(五分钟教你终极算法---分代搜集算法)
  9. [翻译]More C++ Idioms - 类成员检测器
  10. 作者:崔辰州(1976-),男,博士,中国科学院国家天文台研究员、硕士生导师...
  11. MyBatis学习 之 三、动态SQL语句
  12. Objective-C之数组
  13. php7 memcached sasl,Mac安装memcached扩展支持sasl
  14. Logistic Regression(逻辑回归)模型实现二分类和多分类
  15. 英语总结系列(二十一):英语也能玩出新花样
  16. AOP Aspect Oriented Programming
  17. 【写作技巧】毕业论文格式要求
  18. pythonnet 引用_Python netmiko模块的使用
  19. 北斗导航 | RAIM算法之奇偶矢量法(原理讲解,附代码链接:可用性判定)
  20. OpenCV快速入门六:图解Numpy

热门文章

  1. Android理解(一)自定义控件皮肤的原理
  2. AutoLisp从入门到放弃(五)
  3. mysql数据库存储表情都是问号_数据库保存中文全为问号以及emoji表情保存出错...
  4. 深度学习环境配置 (Ubuntu18.04 + CUDA10.0 + cuDNN7.6.5 + TensorFlow2.0)
  5. 波兰科研人员提出可准确区分活人与死人的虹膜识别技术
  6. 4.8nbsp;自由经济与凯恩斯主义
  7. Java 必知 EE与SE的区别
  8. mybatis-plus入门,熟练掌握 MyBatis-Plus,一篇就够!
  9. 利用莎士比亚数据集进行RNN文本生成的训练
  10. 非三族非五族元素在硅和锗中的作用