基于Spring MVC的接口开发【开发实践】

目录

一、MVC简介(了解)

1.1 什么是MVC

MVC是一种设计模式、软件架构思想,将软件划分为三层:模型(Model),视图(View),控制器(Controller)。

1.2 MVC中三层职责

模型(Model):负责处理数据和业务逻辑,包括对数据的存储、读取、验证等操作。模型是应用程序的核心组件,与视图和控制器相互独立,可以被其他应用程序重复使用。

视图(View):负责显示用户界面,将数据呈现给用户。视图通常是根据模型中的数据生成的,可以根据需要进行定制和修改。

控制器(Controller):负责协调和管理模型和视图之间的交互,并处理用户输入和操作。控制器接收用户的请求,更新模型和视图,将结果返回给用户。

1.3 MVC的流程

  1. 用户发送请求,请求由控制器接收并处理
  2. 控制器根据用户请求选择相应的模型和视图,并将请求传递给模型
  3. 模型根据请求处理数据,并将处理结果返回给控制器
  4. 控制器根据模型返回的数据更新视图,并将更新后的视图返回给用户

二、Spring MVC简介(了解)

2.1 Spring MVC与MVC的关系

Spring MVC对这套MVC流程进行封装,帮助开发者屏蔽底层细节,并且开放出相关接口供开发者调用,让MVC开发更简单方便。

2.2 Spring MVC的三层架构

Spring MVC将服务器端分成了三层:表现层(Controller)、业务逻辑层(Service)、持久层(Dao)。其中,表现层通过调用业务层来处理请求并响应结果,业务层负责封装业务代码和事务控制,持久层专注于与数据库的交互。

2.3 Spring MVC的核心组件(x8)

1. DispatcherServlet(前端控制器):负责从请求到响应的整个过程的流程控制
2. Handler(处理器):负责处理特定的请求。处理器有多种类型,如注解申明的处理器,实现Controller接口得到的处理器,Servlet对应的处理器等
3. HandlerMapping(处理器映射器):负责将请求映射到对应的处理器,但并不是简单地直接返回处理器,而是将该处理器和多个拦截器(HandlerInterceptor)封装成一个处理器执行链(HandlerExecuteChain)并返回
4. HandlerAdapter(处理器适配器):调用Handler处理请求,执行业务方法之前,HandlerAdapter还会进行一系列的操作,包括表单的数据验证、数据类型转换、把表单数据封装到POJO等。有多种处理器适配器,每种处理器适配器负责一类处理器,调用处理器的逻辑不同。通过适配器模式对Handler进行适配,来对上层组件隐藏实际的调用逻辑
5. HandlerInterceptor(处理器拦截器):是一个接口,当需要对请求进行一些拦截处理时,可以通过实现该接口完成(由DispatcherServlet调用,在Handler执行前后进行一些处理)
6. ModelAndView(模型和视图):封装了模型数据和视图信息,作为Handler的处理结果,返回给DispatcherServlet
7. ViewResolver(视图解析器):进行视图解析,根据逻辑视图名解析成真正的视图(view)
8. View(视图):完成渲染并生成Response对象

2.4 Spring MVC的工作流程

Spring MVC用于提供服务,一个服务需要经过:接收请求->处理请求->响应结果
提供服务的具体流程见下(对于每一步,关注于谁调用谁,完成了什么工作)

业务处理的工作流程(七步)(重要)

  1. 浏览器发出HttpRequest请求到DispatcherServlet
  2. DispatcherServlet会先调用HandlerMapping
  3. HandlerMapping找到请求对应的Handler,然后生成相应的HandlerExecuteChain返回给DispatcherServlet
  4. DispatcherServlet调用HandlerExecuteChain中的Handler对应的HandlerAdapter
  5. HandlerAdapter会调用Handler(后端控制器Controller的方法)处理请求
  6. Handler处理请求,并将处理结果和要跳转的视图封装为ModelAndView返回给HandlerAdapter
  7. HandlerAdapter将ModelAndView返回给DispatcherServlet,至此,业务处理完成

响应结果的工作流程(四步)

  1. DispatcherServlet将ModelAndView传给ViewReslover
  2. (解析)ViewResolver进行解析,并返回具体的View给DispatcherServlet
  3. (渲染)DispatcherServlet调用View,让其自己进行渲染,并生成响应对象HttpResponse
  4. (响应)DispatcherServlet将HttpResponse响应给浏览器,展示结果

三、接口开发初级:写一个接口

主要工作:写一个Controller类,在该类中写方法,每个方法对应一个请求

3.1 标记Controller

@Controller:将一个类标记为Controller层的组件,Spring会为其创建Bean并交由Ioc容器管理
@RestController:可视为@Controller和@ResponseBody的组合,相当于在类上用@Controller,再在类中的所有方法上用@ResponseBody。@ResponseBody会将controller的方法返回的对象通过适当的转换器转换为指定的格式(JSON或XML),然后将其放入response对象的body区中

3.2 请求映射(基于注解版)

两大注解

@RequestMapping:既可以作用于类上,也可以作用于方法上,从而可以表示层级关系。有两个常用的属性:value和method。value有个别名path,用于指定url。method用于限定请求方法,使用“RequestMethod.GET”的方式设置值,不使用时不限定请求方法
@GetMapping、@PostMapping等:只能作用于方法上,用于映射限定了请求方法的方法

url值的复杂规则

正斜杠的使用。当配置的url以“/”开头时,会从项目根路径开始查找,否则是从当前方法所在层级开始查找(类似linux命令中的路径)。
Ant风格。“*”表示可以匹配单层目录下的任意字符(可以没有),必须配合正斜杠使用;“**”表示单层或多层目录下的任意字符(可以没有),可以不配合正斜杠使用;“?”表示匹配任意单个字符(必须有)。
Rest风格。url中可以使用“{变量名}”的方式传参数,然后结合@PathVariable{变量名}使用来取出参数。还可以使用“{变量名:正则}”的方式来限定参数格式。
多url。可以使用@RequestMapping(path={“url1”,…,“urln”})的方式设置多个url。

3.3 Controller方法的返回值类型

四种情形/返回值类型

ModelAndView:此时返回的是数据模型和视图
String:值为“forward:url”时,对应url转发的情形;值为“redirect:url”时,对应url重定向的情形;若不是上述两种情形,表明返回的是视图名称
void:此时会将请求的url作为视图名称
Object:表示返回的是数据模型(一般返回json数据)

实际开发时的返回值

一般公司会对返回值类型封装为一个泛型类,如BizResponse<T>,T为填充的数据类型,不需要返回数据时用Void即可
该泛型类中包含三个重要信息:状态码(int code),提示信息(String message)和数据(T data)。
需要返回数据时返回BizResponse.success(data),不需要返回数据时返回BizResponse.success()

3.4 参数获取(八大传参方式)

Params传参

传输参数:http://url?参数1名=值1&参数2名=值2
获取参数:使用@RequestParam来获取参数,该注解有value、required和defaultValue三个属性,其中required默认为true。若没有使用value属性,则其默认值为该注解作用的变量名

URL传参(RESTFul风格)

传输参数:http://url/{参数1名}/{参数2名}
获取参数:使用@PathVariable来获取参数,该注解有value和name两个属性,该两个属性互为别名,用于指定需要获取的参数的参数名

表单传参

传输参数:将键值对放入request的body中传输数据,格式选择form-data。
获取参数:使用@RequestParam来获取参数

文件传输

传输参数:input的type属性设置为file,form表单的method设置为post,form表单的enctype设置为multipart/form-data
获取参数:使用@RequestPart(“key”)来获取参数,参数格式为“MultipartFile file”

json传参

传输参数:将键值对放入request的body中传输数据,格式选择raw(JSON)
获取参数:使用@RequestBody来获取参数,该注解只有value这一个属性,默认为true。@RequestBody作用于在一个POJO上,根据key-value找打对象的同名属性并赋值为value

请求头传参

传输参数:将数据以键值对形式放入request的head区(请求头)
获取参数:使用@RequestHeader来获取请求头中的数据

Cookie传参

Cookie概述:Cookie是一个键值对(不是一组),可以有多个Cookie在服务器和浏览器之间传递。在服务器设置会存储在response中返回给浏览器,浏览器在每次请求时会自动带上所有的Cookie到request中
设置Cookie:先Cookie cookie = new Cookie(“key”, “value”),再加入到response,既response.addCookie(cookie)
获取所有Cookie:Cookie[] cookies = request.getCookies[]
获取指定Cookie的值:在Controller方法的形参上使用@CookieValue(“key”)来注入该Cookie对应的值

Session传参

Session概述:服务器为每一个浏览器创建一个session,且只有一个session,里面存储了一组键值对(区别于Cookie)
设置Session:在方法中使用HttpSession sessoin来获取Session,Spring会自动注入该对象。使用Session对象调用setAttribute(“key”,“value”)来设置键值对数据,并且可以使用 session.setMaxInactiveInterval(30*60)来设置过期时间(超时未访问就会自动过期)
获取Session:在方法中使用HttpSession sessoin来获取Session,使用Session对象调用getAttribute(“key”)来获取数据。此外,还可以使用@SessionAttributes(“变量名”)来注入对应值,该注解作用于类上时,会将Controller方法中的同名变量放入到Session中,在同一个会话中可以共享使用,无需反复传参。该注解也可以作用于方法参数上

通过HttpServletRequest获取数据

可以在方法中使用HttpServletRequest来获取HttpServletRequest对象,Spring会自动注入该对象。该对象中有请求的所有信息,从而可以获取想要的数据

补充:Controller方法中可以自动注入/获取的参数

  1. JAVAEE组件:HttpServletRequest,HttpServletResponse,HttpSession
  2. 向界面传递数据的对象:Model,Map,ModelMap(作用域都是request)
  3. IO流:InputStream/OutputStream,Reader/Writer(通过request/response获取)

四、接口开发中级:提高接口的质量

4.1 服务端数据校验

使用流程

  1. 加入Maven依赖
  2. 在需要校验的参数上使用@Valid注解
  3. 在该参数类型对应类中使用注解进行校验规则配置

六类常见校验规则及其对应注解

空检查

@NULL :验证对象是否为null
@NotNull:验证对象是否不为null

布尔检查

@AssertTrue:验证Boolean对象是否为true
@AssertFalse:验证Boolean对象是否为false

长度检查

@Size(min=,max=):验证集合对象中的元素是否在指定范围内(闭区间)
@Length(min=,max=):验证字符串对象的长度是否在指定范围内(闭区间)
@NotEmpty:验证集合对象是否不为null且元素个数大于零
@NotBlank:验证字符串对象是否不为null且去掉首尾空格后长度大于零

日期检查

@Past :验证Date和Calendar对象是否在当前时间之前
@Future:验证Date和Calendar对象是否在当前时间之后
@Pattern:验证String对象是否符合正则表达式的规则

数值检查

@Min:验证Number和String对象是否大等于指定的值
@Max:验证Number和String对象是否小等于指定的值
@Range(min=, max=,message=):验证对象是否在指定范围内
@DecimalMin:验证BigDecimal对象是否大于等于指定值
@DecimalMax:验证BigDecimal对象是否小于等于指定值
@Valid:递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验

格式验证

@CreditCardNumber:信用卡验证
@Email:验证是否是邮件地址,如果为null,不进行验证,算通过验证
@Digits(integer=,fraction=):验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度

4.2 统一异常处理

Spring MVC提供了统一异常处理,方式如下:

  1. 使用@ControllerAdvice标记类,表明其为异常处理类(控制器通知类)
  2. 使用@ExceptionHandler标记一个方法,并定义异常处理方法:使用属性值设置需要处理的异常类型,方法中则可以进行异常处理和打印异常信息,方法的返回值为一个jsp页面名,会对指定视图进行渲染并显示

4.3 打印日志(以Slf4j为例)

使用方式

使用Lombok提供的注解@Slf4j,该注解作用于类上,可以在在类中自动生成一个名为log的日志对象(类变量),在类中的任意位置可以使用log对象打印日志(如log.dedug())

使用规范

  1. 日志级别只允许使用ERROR、WARN、INFO、DEBUG
  2. 为减少开销,打印日志时建议使用占位符的方式拼装内容,而不是字符串拼接
  3. 打印日志时,不建议使用JSON工具将对象转换成String,如果对象里某些get方法被覆写,存在抛出异常的风险,进而影响正常业务流程
  4. 异常日志内容中应当包含三要素:异常场景(如登录失败)、异常数据(如用户id)、异常堆栈(就是e)

四类日志的使用场景

ERROR:业务功能受损或无法完成预期操作,可能会造成线上故障需要预警并及时解决,否则该功能将无法正常运行
WARN:异常符合预期的情况且业务不受损,不会出现线上故障,可根据实际情况选择性预警,解决时效要求不高,但需要关注
INFO:用于记录系统运行过程或重要信息点,主要为故障定位表示用于记录系统运行过程或重要信息点,主要为故障定位、过程追溯、数据分析等提供辅助能力
DEBUG:表示用于在测试或本地的非生产环境中使用,可以记录详细的信息,主要为了方便开发调试程序,而在生产环境中禁止使用

五、接口开发高级:更多功能的支持

5.1 事务管理

// to do

5.2 拦截器开发

// to do

5.3 文件的上传和下载

// to do(需要用到时再学习并补充这些内容~)

5.4 数据类型转换

// to do

六、开发接口收尾:交付接口

6.1 接口文档(基于Swagger)

常用注解(暂时只需要用如下两个)

@Api:对Controller类进行描述(使用tags属性)
@ApiOperation:对Controller类中的方法进行描述(使用value属性)

6.2 接口测试

流程

  1. 写一个测试类的基类BaseTest,需要完成如下工作:使用@SpringBootTest(…)标记,表明该类及其子类为Spring Boot的测试类;使用@AutoConfigureMockMvc标记,用于注入MockMvc对象
  2. 为某个Controller写一个对应的测试类,继承自BaseTest
  3. 为每个接口写一个测试方法,使用public void修饰,需要throw Exception,并使用@Test标记
  4. 完成测试方法的实现(详情见后)

使用mockMVC完成测试

  1. 使用mockMVC.perform(…)执行模拟的HTTP请求
  2. 具体要模拟的请求,如post请求,可以使用MockMvcRequestBuilders.post(url)来生成,同时支持流式操作,调用param()、header()和content()等方法来分别设置请求的参数、请求头和请求体
  3. 在执行模拟的HTTP请求后,可以使用(多个).andExpect()(以流式操作完成断言)来验证预期的响应,其中HTTP状态码、响应头、响应体是最常用的验证指标
  4. 最后可以使用.andReturn(),会返回MvcResult对象,使用该对象调用getResponse().getContentAsString()获得String类型的响应文本,并结合断言Assert.assertTrue(content.equals(“xxx”))来验证响应文本是否符合预期
  5. 如果不验证响应文本,也可以使用.andDo(print())打印结果

Post方法接口的测试案例(需要传输json数据的情形)

@Test
public void testConnectWithBody() throws Exception {
	// 提前准备请求所需的json数据,这里需要的json字符串格式
	// 可以使用bean或map转json字符串,也可以自己拼装
    MockMVCInfo mockMVCInfo = new MockMVCInfo();
    mockMVCInfo.setId(3L);
    mockMVCInfo.setName("MockMVC");
    String json = JSON.toJSONString(mockMVCInfo));
    
    // 执行
    MvcResult mvcResult = mockMvc.perform(
    		// 模拟HTTP请求
            MockMvcRequestBuilders.post("/mockMcv/connect/withBody")
            		// 使用header设置授权令牌
            		.header(HttpHeaders.AUTHORIZATION, InitAuthorization.AUTHORIZATION)
                    // 使用body传输json数据时,需要指定header中的Content-Type为application/json
                    .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                    // 在请求体中放入json字符串
                    .content(json)
            // 验证HTTP状态码
            .andExpect(MockMvcResultMatchers.status().isOk())
            // 验证响应体中的code(区别于HTTP状态码)
            .andExpect(jsonPath("$.code", is(BizErrorCodeEnum.SUCCESS.getCode())))
            // 返回MvcResult对象
            .andReturn();
    
    // 获取响应文本
    String content = mvcResult.getResponse().getContentAsString();
    // 验证响应本文
    Assert.assertTrue(content.contains("MockMVC"));
}

参考博客推荐

  1. SpringMVC工作流程(详-小白版)
  2. Spring MVC详解(学习总结)
  3. SpringMVC学习:控制层(Controller)基于注解详解
  4. 【框架篇】Spring MVC 介绍及使用(详细教程)
  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值