当前位置: 首页 > news >正文

SpringBoot3之Web编程

标签:Rest.拦截器.swagger.测试;

一、简介

基于web包的依赖,SpringBoot可以快速启动一个web容器,简化项目的开发;

web开发中又涉及如下几个功能点:

拦截器:可以让接口被访问之前,将请求拦截到,通过对请求的识别和校验,判断请求是否允许通过;

页面交互:对于服务端的开发来说,需要具备简单的页面开发能力,解决部分场景的需求;

Swagger接口:通过简单的配置,快速生成接口的描述,并且提供对接口的测试能力;

Junit测试:通过编写代码的方式对接口进行测试,从而完成对接口的检查和验证,并且可以不入侵原代码结构;

二、工程搭建

1、工程结构

2、依赖管理

<!-- 基础框架组件 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring-boot.version}</version>
</dependency>
<!-- 接口文档组件 -->
<dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId><version>${springdoc.version}</version>
</dependency>
<!-- 前端页面组件 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><version>${spring-boot.version}</version>
</dependency>
<!-- 单元测试组件 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>${spring-boot.version}</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version>
</dependency>

三、Web开发

1、接口开发

编写四个简单常规的接口,从对资源操作的角度,也就是常说的:增Post、删Delete、改Put、查Get,并且使用了swagger注解,可以快速生成接口文档;

@RestController
@Tag(name = "Rest接口")
public class RestWeb {@Operation(summary = "Get接口")@GetMapping("rest/get/{id}")public String restGet(@PathVariable Integer id) {return "OK:"+id;}@Operation(summary = "Post接口")@PostMapping("/rest/post")public String restPost(@RequestBody ParamBO param){return "OK:"+param.getName();}@Operation(summary = "Put接口")@PutMapping("/rest/put")public String restPut(@RequestBody ParamBO param){return "OK:"+param.getId();}@Operation(summary = "Delete接口")@DeleteMapping("/rest/delete/{id}")public String restDelete(@PathVariable Integer id){return "OK:"+id;}
}

2、页面交互

对于服务端开发来说,在部分场景下是需要进行简单的页面开发的,比如通过页面渲染再去生成文件,或者直接通过页面填充邮件内容等;

数据接口

@Controller
public class PageWeb {@RequestMapping("/page/view")public ModelAndView pageView (HttpServletRequest request){ModelAndView modelAndView = new ModelAndView() ;// 普通参数modelAndView.addObject("name", "cicada");modelAndView.addObject("time", "2023-07-12");// 对象模型modelAndView.addObject("page", new PageBO(7,"页面数据模型"));// List集合List<PageBO> pageList = new ArrayList<>() ;pageList.add(new PageBO(1,"第一页"));pageList.add(new PageBO(2,"第二页"));modelAndView.addObject("pageList", pageList);// Array数组PageBO[] pageArr = new PageBO[]{new PageBO(6,"第六页"),new PageBO(7,"第七页")} ;modelAndView.addObject("pageArr", pageArr);modelAndView.setViewName("/page-view");return modelAndView ;}
}

页面解析:分别解析了普通参数,实体对象,集合容器,数组容器等几种数据模型;

<div style="text-align: center"><hr/><h5>普通参数解析</h5>姓名:<span th:text="${name}"></span>时间:<span th:text="${time}"></span><hr/><h5>对象模型解析</h5>整形:<span th:text="${page.getKey()}"></span>字符:<span th:text="${page.getValue()}"></span><hr/><h5>集合容器解析</h5><table style="margin:0 auto;width: 200px"><tr><th>Key</th><th>Value</th></tr><tr th:each="page:${pageList}"><td th:text="${page.getKey()}"></td><td th:text="${page.getValue()}"></td></tr></table><hr/><h5>数组容器解析</h5><table style="margin:0 auto;width: 200px"><tr><th>Key</th><th>Value</th></tr><tr th:each="page:${pageArr}"><td th:text="${page.getKey()}"></td><td th:text="${page.getValue()}"></td></tr></table><hr/>
</div>

效果图展示

四、拦截器

1、拦截器定义

通过实现HandlerInterceptor接口,完成对两个拦截器的自定义,请求在访问服务时,必须通过两个拦截器的校验;

/*** 拦截器一*/
public class HeadInterceptor implements HandlerInterceptor {private static final Logger log  = LoggerFactory.getLogger(HeadInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {log.info("HeadInterceptor:preHandle");Iterator<String> headNames = request.getHeaderNames().asIterator();log.info("request-header");while (headNames.hasNext()){String headName = headNames.next();String headValue = request.getHeader(headName);System.out.println(headName+":"+headValue);}// 放开拦截return true;}@Overridepublic void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler, ModelAndView modelAndView) throws Exception {log.info("HeadInterceptor:postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler, Exception e) throws Exception {log.info("HeadInterceptor:afterCompletion");}
}/*** 拦截器二*/
public class BodyInterceptor implements HandlerInterceptor {private static final Logger log  = LoggerFactory.getLogger(BodyInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {log.info("BodyInterceptor:preHandle");Iterator<String> paramNames = request.getParameterNames().asIterator();log.info("request-param");while (paramNames.hasNext()){String paramName = paramNames.next();String paramValue = request.getParameter(paramName);System.out.println(paramName+":"+paramValue);}// 放开拦截return true;}@Overridepublic void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler, ModelAndView modelAndView) throws Exception {log.info("BodyInterceptor:postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler, Exception e) throws Exception {log.info("BodyInterceptor:afterCompletion");}
}

2、拦截器配置

自定义拦截器之后,还需要添加到web工程的配置文件中,可以通过实现WebMvcConfigurer接口,完成自定义的配置添加;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {/*** 添加自定义拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new HeadInterceptor()).addPathPatterns("/**");registry.addInterceptor(new BodyInterceptor()).addPathPatterns("/**");}
}

五、测试工具

1、Swagger接口

添加上述的springdoc依赖之后,还可以在配置文件中简单定义一些信息,访问IP:端口/swagger-ui/index.html即可;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {/*** 接口文档配置*/@Beanpublic OpenAPI openAPI() {return new OpenAPI().info(new Info().title("【boot-web】").description("Rest接口文档-2023-07-11").version("1.0.0"));}
}

2、Junit测试

在个人的习惯上,Swagger接口文档更偏向在前后端对接的时候使用,而Junit单元测试更符合开发的时候使用,这里是对RestWeb中的接口进行测试;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class RestWebTest {@Autowiredprivate MockMvc mockMvc;@Testpublic void testGet () throws Exception {// GET接口测试MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/rest/get/1")).andReturn();printMvcResult(mvcResult);}@Testpublic void testPost () throws Exception {// 参数模型JsonMapper jsonMapper = new JsonMapper();ParamBO param = new ParamBO(null,"单元测试",new Date()) ;String paramJson = jsonMapper.writeValueAsString(param) ;// Post接口测试MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/rest/post").contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).content(paramJson)).andReturn();printMvcResult(mvcResult);}@Testpublic void testPut () throws Exception {// 参数模型JsonMapper jsonMapper = new JsonMapper();ParamBO param = new ParamBO(7,"Junit组件",new Date()) ;String paramJson = jsonMapper.writeValueAsString(param) ;// Put接口测试MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.put("/rest/put").contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).content(paramJson)).andReturn();printMvcResult(mvcResult);}@Testpublic void testDelete () throws Exception {// Delete接口测试MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.delete("/rest/delete/2")).andReturn();printMvcResult(mvcResult);}/*** 打印【MvcResult】信息*/private void printMvcResult (MvcResult mvcResult) throws Exception {System.out.println("请求-URI【"+mvcResult.getRequest().getRequestURI()+"】");System.out.println("响应-status【"+mvcResult.getResponse().getStatus()+"】");System.out.println("响应-content【"+mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8)+"】");}
}

六、参考源码

文档仓库:
https://gitee.com/cicadasmile/butte-java-note源码仓库:
https://gitee.com/cicadasmile/butte-spring-parent

相关文章:

SpringBoot3之Web编程

标签&#xff1a;Rest.拦截器.swagger.测试; 一、简介 基于web包的依赖&#xff0c;SpringBoot可以快速启动一个web容器&#xff0c;简化项目的开发&#xff1b; 在web开发中又涉及如下几个功能点&#xff1a; 拦截器&#xff1a;可以让接口被访问之前&#xff0c;将请求拦截…...

策略模式(C++)

定义 定义一系列算法&#xff0c;把它们一个个封装起来&#xff0c;并且使它们可互相替换((变化)。该模式使得算法可独立手使用它的客户程序稳定)而变化(扩展&#xff0c;子类化)。 ——《设计模式》GoF 使用场景 在软件构建过程中&#xff0c;某些对象使用的算法可能多种多…...

【每日一题Day290】LC1281整数的各位积和之差 | 模拟

整数的各位积和之差【LC1281】 给你一个整数 n&#xff0c;请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。 思路&#xff1a;简单模拟 循环取余&#xff0c;计算「各位数字之积」与「各位数字之和」&#xff0c;最后求差返回 实现 class Solution {public…...

揭示CTGAN的潜力:利用生成AI进行合成数据

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可编辑的3D应用场景 我们都知道&#xff0c;GAN在生成非结构化合成数据&#xff08;如图像和文本&#xff09;方面越来越受欢迎。然而&#xff0c;在使用GAN生成合成表格数据方面所做的工作很少。合成数据具有许多好处&#x…...

GitHub中readme.md文件的编辑和使用

GitHub中readme.md文件的编辑和使用 | YuuiChungs BlogGitHub - guodongxiaren/README: README文件语法解读&#xff0c;即Github Flavored Markdown语法介绍...

Python 四舍五入到最接近的十位

本篇文章将讨论使用 Python 的 ceil() 函数将数字四舍五入到最接近的十。 Python 整数到最接近的十 Python 具有三个内置函数 round()、floor() 和 ceil()&#xff0c;可用于对数字进行舍入。 ceil() 函数属于数学模块&#xff0c;用于将浮点数舍入为大于或等于给定数字的最接…...

Unity限制在一个范围内移动

Unity限制在一个范围内移动 这个例子中&#xff0c;我们学习Vector3.ClampMagnitude的用法&#xff0c;限制小球在范围内移动。 在地图上放了一个小球&#xff0c;让他移动&#xff0c;但是不想让他掉下去&#xff0c;限制在一个球星范围内&#xff0c;就好像绳子拴住了一样&…...

dji uav建图导航系列(一)建图

文章目录 1、uav + rplidir雷达1.2、思岚激光雷达1.3、dji uav的launch文件2、cartographer激光建图2.1、启动文件2.2、config修改2.3、建图过程3、融合odom+laser建图1、uav + rplidir雷达 思岚激光雷达frame为base_laser_link, 无人机frame为base_footprint。 文件uav_lid…...

AAAI论文阅读

文章目录 Open-Vocabulary Multi-Label Classifcation via Multi-Modal Knowledge Transfer——知识蒸馏的范畴Med-EASi: Finely Annotated Dataset and Models for Controllable Simplifcation of Medical Texts——医学领域数据集构建“Nothing Abnormal”: Disambiguating M…...

填补5G物联一张网,美格智能快速推进RedCap商用落地

自5G R17版本标准冻结以来&#xff0c;RedCap一直引人注目。2023年更是5G RedCap突破性发展的一年&#xff0c;从首款5G RedCap调制解调器及射频系统——骁龙X35发布&#xff0c;到国内四大运营商发布RedCap技术白皮书&#xff0c;芯片厂商、模组厂商、运营商及终端企业都在积极…...

服务器杂七杂八的知识/常识归纳(不断更新)

一.pID与端口号不一样吗? pID&#xff08;Process ID&#xff0c;进程标识符&#xff09;和端口号是不同的概念。 pID是操作系统中用来唯一标识一个正在运行的进程的数字。每个正在运行的进程都会被分配一个唯一的pID&#xff0c;它可以用来追踪和管理进程。 而端口号是在网…...

掌握Java排序算法:实现主流排序方法与性能对比

一&#xff0c;C语言&#xff0c;主流的排序方法介绍 当谈论主流的排序方法时&#xff0c;通常指的是在实际应用中表现优秀且被广泛采用的排序算法。以下是常见的主流排序方法及其介绍、时间复杂度、空间复杂度和简单的C语言代码实现&#xff1a; 冒泡排序&#xff08;Bubble S…...

jdk17 SpringBoot JPA集成多数据库

switchRegion(切换地区)功能, 客户端可手动切换地区 , 查询不同的数据库, 后台根据地区切换数据库, 请求头添加region的key 配置类 import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; im…...

vue 新学习 06 js的prototype ,export暴露,vue组件,一个重要的内置关系

01 在js中&#xff1a; 原型链 注意&#xff1a;构造函数.prototype实例化对象.__proto__&#xff0c;都是指向函数的原型。 export&#xff1a; -export用于对外输出本模块&#xff08;一个文件可以理解为一个模块&#xff09;变量的接口 -import用于在一个模块中加载另一个…...

冠达管理:“高温超导”不是“室温超导”,5天4板百利电气再次澄清

短短半个月&#xff0c;“室温超导”在惊喜、质疑间回转&#xff0c;但资本市场对“超导概念股”的炒作还在进行&#xff0c;8月7日室温超导概念持续疯涨。同花顺显现&#xff0c;到8月7日收盘&#xff0c;18只超导概念股中&#xff0c;有16只股票飘红。 广东研山私募证券投资&…...

CS 144 Lab Four 收尾 -- 网络交互全流程解析

CS 144 Lab Four 收尾 -- 网络交互全流程解析 引言Tun/Tap简介tcp_ipv4.cc文件配置信息初始化cs144实现的fd家族体系基于自定义fd体系进行数据读写的adapter适配器体系自定义socket体系自定义事件循环EventLoop模板类TCPSpongeSocket详解listen_and_accept方法_tcp_main方法_in…...

Linux面试专题

Linux面试专题 1 Linux中主要有哪几种内核锁?2 Linux 中的用户模式和内核模式是什么含意?3 怎样申请大块内核内存?4用户进程间通信主要哪几种方式?5通过伙伴系统申请内核内存的函数有哪些?6) Linux 虚拟文件系统的关键数据结构有哪些?(至少写出四个)7) 对文件或设备的操作…...

MySQL错误日志(Error Log)详解

错误日志&#xff08;Error Log&#xff09;是 MySQL 中最常用的一种日志&#xff0c;主要记录 MySQL 服务器启动和停止过程中的信息、服务器在运行过程中发生的故障和异常情况等。 作为初学者&#xff0c;要学会利用错误日志来定位问题。下面介绍如何操作查看错误日志。 启动…...

Qt应用开发(基础篇)——LCD数值类 QLCDNumber

一、前言 QLCDNumber类继承于QFrame&#xff0c;QFrame继承于QWidget&#xff0c;是Qt的一个基础小部件。 QLCDNumber用来显示一个带有类似lcd数字的数字&#xff0c;适用于信号灯、跑步机、体温计、时钟、电表、水表、血压计等仪器类产品的数值显示。 QLCDNumber可以显示十进制…...

新版百度、百家号旋转验证码识别

昨天突然发现&#xff0c;百度旋转验证码发生了变化&#xff0c;导致使用老版本验证码训练出来的识别模型效果不佳。所有昨天花了一天时间完成了新版模型的训练。 老版本验证码 新版本验证码 新版的验证码感觉像是AI绘画随机生成的&#xff0c;还有随机阴影出现。 验证码识别…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

redis和redission的区别

Redis 和 Redisson 是两个密切相关但又本质不同的技术&#xff0c;它们扮演着完全不同的角色&#xff1a; Redis: 内存数据库/数据结构存储 本质&#xff1a; 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能&#xff1a; 提供丰…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...

土建施工员考试:建筑施工技术重点知识有哪些?

《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目&#xff0c;核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容&#xff0c;附学习方向和应试技巧&#xff1a; 一、施工组织与进度管理 核心目标&#xff1a; 规…...

【iOS】 Block再学习

iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...