瑞吉外卖项目学习笔记(二)Swagger、logback、表单校验和参数打印功能的实现

瑞吉外卖项目学习笔记(一)准备工作、员工登录功能实现

文章目录

  • 3 项目组件优化
    • 3.1 实现Swagger文档输出
    • 3.2 实现logback日志打印
    • 3.3 实现表单校验功能
    • 3.4 实现请求参数和响应参数的打印

3 项目组件优化

3.1 实现Swagger文档输出

  • 1)在application.yml中增加knife4j配置
spring:mvc:pathmatch:matching-strategy: ANT_PATH_MATCHER
knife4j:enable: truetitle: 瑞吉外卖group: ruiji_takeoutdescription: 瑞吉外卖version: 1.0name: itweidurl:email:base-package: com.itweid.takeout.controller
  • 2)创建配置类SwaggerProperties类接收配置
@Data
@ConfigurationProperties(prefix = "knife4j")
public class SwaggerProperties {private String title = ""; //标题private String group = ""; //组名private String description = ""; //描述private String version = ""; //版本private String name = ""; // 联系人private String url = ""; // 联系人urlprivate String email = ""; // 联系人emailprivate String basePackage = ""; //swagger会解析的包路径private List<String> basePath = new ArrayList<>(); //swagger会解析的url规则private List<String> excludePath = new ArrayList<>(); //在basePath基础上需要排除的url// 如果没有填写组名,则直接用标题作为组名public String getGroup() {if (group == null || group.isEmpty()) {return title;}return group;}
}
  • 3)创建自动配置类SwaggerAutoConfiguration进行初始化
@Configuration
@ConditionalOnProperty(name = "knife4j.enable", havingValue = "true", matchIfMissing = true)
@EnableSwagger2
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerAutoConfiguration implements BeanFactoryAware {@Autowiredprivate SwaggerProperties swaggerProperties;@Autowiredprivate BeanFactory beanFactory;@Bean@ConditionalOnMissingBeanpublic List<Docket> createRestApi(){ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;List<Docket> docketList = new LinkedList<>();ApiInfo apiInfo = new ApiInfoBuilder()// 页面标题.title(swaggerProperties.getTitle())// 创建人.contact(new Contact(swaggerProperties.getName(),swaggerProperties.getUrl(),swaggerProperties.getEmail()))// 版本号.version(swaggerProperties.getVersion())// 描述.description(swaggerProperties.getDescription()).build();Docket docket = new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo).groupName(swaggerProperties.getGroup()).select()// 为当前包路径.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())).paths(PathSelectors.any()).build();configurableBeanFactory.registerSingleton(swaggerProperties.getGroup(), docket);docketList.add(docket);return docketList;}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}
}
  • 4)重新启动项目,在浏览器访问http://localhost:8081/doc.html,即可查看Swagger文档:


在Swagger文档的调试功能中,可以直接进行测试:

3.2 实现logback日志打印

  • 1)引入依赖
<!--logback-->
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version>
</dependency>
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.2.3</version>
</dependency>
  • 2)在resources目录下创建配置文件

  • logback-base.xml

<?xml version="1.0" encoding="UTF-8"?>
<included><contextName>logback</contextName><!--name的值是变量的名称,value的值时变量定义的值定义变量后,可以使“${}”来使用变量--><property name="log.path" value="logs" /><!-- 彩色日志 --><!-- 彩色日志依赖的渲染类 --><conversionRuleconversionWord="clr"converterClass="org.springframework.boot.logging.logback.ColorConverter" /><conversionRuleconversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /><conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" /><!-- 彩色日志格式 --><property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/><!--输出到控制台--><appender name="LOG_CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><Pattern>${CONSOLE_LOG_PATTERN}</Pattern><!-- 设置字符集 --><charset>UTF-8</charset></encoder></appender><!--输出到文件--><appender name="LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 正在记录的日志文件的路径及文件名 --><file>${log.path}/Business.log</file><!--日志文件输出格式--><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern><charset>UTF-8</charset></encoder><!-- 日志记录器的滚动策略,按日期,按大小记录 --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 每天日志归档路径以及格式 --><fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>100MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy><!--日志文件保留天数--><maxHistory>15</maxHistory></rollingPolicy></appender>
</included>
  • logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--引入其他配置文件--><include resource="logback-base.xml" /><!--<logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。<logger>仅有一个name属性,一个可选的level和一个可选的addtivity属性。name:用来指定受此logger约束的某一个包或者具体的某一个类。level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,如果未设置此属性,那么当前logger将会继承上级的级别。addtivity:是否向上级logger传递打印信息。默认是true。--><!--开发环境--><springProfile name="dev"><logger name="com.itweid.takeout" additivity="false" level="debug"><appender-ref ref="LOG_CONSOLE"/></logger></springProfile><!--生产环境--><springProfile name="pro"><logger name="com.itweid.takeout" additivity="false" level="info"><appender-ref ref="LOG_FILE"/></logger></springProfile><!--root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性level:设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF 默认是DEBUG可以包含零个或多个元素,标识这个appender将会添加到这个logger。--><root level="info"><appender-ref ref="LOG_CONSOLE" /><appender-ref ref="LOG_FILE" /></root>
</configuration>
  • 3)重新启动项目,可以看到根目录下生成了logs文件夹及日志文件:

3.3 实现表单校验功能

员工登录时,必须输入用户名和密码,虽然前端JS进行了校验,但对于后端来说,前端传来的数据是不可信的。

前端很容易获取到后端的接口,如果有人直接调用接口,就可能会出现非法数据,因此服务端也要数据校验。总的来说:

  • 前端校验:主要是提高用户体验
  • 后端校验:主要是保证数据安全可靠

Hibernate Validator框架可以以很优雅的方式实现参数的校验,让业务代码和校验逻辑分开,不再编写重复的校验逻辑。

更详细的用法可参考:后台管理系统的通用权限解决方案(五)SpringBoot整合hibernate-validator实现表单校验

  • 1)首先,在LoginForm类中加入表单校验的注解,如字符串类型的参数则用@NotBlank
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("登录表单")
public class LoginForm {@ApiModelProperty("用户名")@NotBlank(message = "用户名不能为空")private String username;@ApiModelProperty("密码")@NotBlank(message = "密码不能为空")private String password;
}
  • 2)在EmployeeController类中使用@Validated注解开启校验功能:

  • 3)需要特别注意的是,在2.3.0版本之前,spring-boot-starter-web是集成了validation检验的,但是在2.3.0开始就去掉了该依赖,所以根据实际版本决定是否添加依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>
  • 4)重启服务,发起登录请求,如果用户名为空,则会报错:


但此时前端提示不太友好(报400)。我们还要继续完善一下,对异常进行统一处理。

  • 5)自定义一个CustomException异常类来统一处理已知的异常。未来在业务逻辑中,使用try...catch...捕获异常后,再抛出一个CustomException异常:
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class CustomException extends RuntimeException {private BaseResult result;/*** 指定一个是否追踪信息栈的异常*/public CustomException(BaseResult result, boolean writableStackTrace) {super(result.getMsg(), null, false, writableStackTrace);this.result = result;}/*** 指定一个不追踪信息栈的异常*/public CustomException(BaseResult result) {super(result.getMsg(), null, false, false);this.result = result;}/*** 指定一个不追踪栈信息的异常*/public CustomException(ErrorCode errorCode) {super(errorCode.getMsg(), null, false, false);this.result = BaseResult.error(errorCode);}
}
  • 6)创建一个全局异常处理类GlobalExceptionHandler,对自定义异常和参数绑定异常进行统一处理:
@ControllerAdvice(annotations = { RestController.class, Controller.class })
@Slf4j
public class GlobalExceptionHandler {/*** 自定义异常的处理*/@ExceptionHandler(CustomException.class)@ResponseBodypublic BaseResult customExceptionHandler(CustomException customException) {log.error("捕获自定义异常:{}", customException.getResult().getMsg(), customException);return customException.getResult();}/*** 参数绑定异常的处理*/@ExceptionHandler({ConstraintViolationException.class, BindException.class})@ResponseBodypublic String validateException(Exception e, HttpServletRequest request) {log.error("捕获参数异常:{}", e.getMessage(), e);String msg = null;if (e instanceof ConstraintViolationException) {ConstraintViolationException constraintViolationException =(ConstraintViolationException) e;Set<ConstraintViolation<?>> violations =constraintViolationException.getConstraintViolations();ConstraintViolation<?> next = violations.iterator().next();msg = next.getMessage();} else if (e instanceof BindException) {BindException bindException = (BindException) e;msg = bindException.getBindingResult().getFieldError().getDefaultMessage();}log.error("参数异常信息:{}", msg);return msg;}}
  • 7)重启服务,再次调用登录请求,当参数不符合要求时,则会返回更加友好的提示:

3.4 实现请求参数和响应参数的打印

页面的每个请求都有请求参数和响应参数,如果每个请求都单独打印这些参数,则显得非常冗余。

为此我们可以基于注解和切面编程,实现请求参数和响应参数的打印。

  • 1)引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--hutool工具-->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.1.0</version>
</dependency>
  • 2)创建切面类OptLogAspect,配置切入点拦截规则,拦截所有Controller方法
@Aspect
@Slf4j
public class OptLogAspect {/*** 定义Controller切入点拦截规则,拦截 @OptLog 注解的方法*/@Pointcut("execution(public * com.itweid.takeout.controller.*Controller.*(..))")public void optLogAspect() {}
}
  • 3)在OptLogAspect的前置通知方法中,打印请求参数信息
/*** 前置通知*/
@Before(value = "optLogAspect()")
public void doBefore(JoinPoint joinPoint) throws Throwable {HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();// 请求参数Object[] args = joinPoint.getArgs();String strArgs = "";try {if (!request.getContentType().contains("multipart/form-data")) {strArgs = JSONUtil.toJsonStr(args);}} catch (Exception e) {try {strArgs = Arrays.toString(args);} catch (Exception ex) {log.warn("解析参数异常", ex);}}log.info("请求参数:{}", StrUtil.sub(strArgs, 0, 65535));
}
  • 4)在成功返回通知方法和异常返回通知中,打印响应参数信息
/*** 成功返回通知*/
@AfterReturning(returning = "ret", pointcut = "optLogAspect()")
public void doAfterReturning(Object ret) {BaseResult baseResult = Convert.convert(BaseResult.class, ret);log.info("响应参数:{}", baseResult);
}/*** 异常返回通知*/
@AfterThrowing(throwing = "e", pointcut = "optLogAspect()")
public void doAfterThrowable(Throwable e) {log.info("响应异常:{}", getStackTrace(e));
}public static String getStackTrace(Throwable throwable) {StringWriter sw = new StringWriter();try (PrintWriter pw = new PrintWriter(sw)) {throwable.printStackTrace(pw);return sw.toString();}
}
  • 5)在WebMvcConfig配置类中注册切面类为Bean
@Bean
public OptLogAspect optLogAspect() {return new OptLogAspect();
}
  • 6)重启服务,测试登录功能


可见,请求参数和响应参数成功打印。后续还可以将请求IP、操作员等信息收集起来存到数据库,就可以实现常说的审计功能。

本节完,更多内容查阅:瑞吉外卖项目实战

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/63564.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于字节大模型的论文翻译(含免费源码)

基于字节大模型的论文翻译 源代码&#xff1a; &#x1f44f; star ✨ https://github.com/boots-coder/LLM-application 展示 项目简介 本项目是一个基于大语言模型&#xff08;Large Language Model, LLM&#xff09;的论文阅读与翻译辅助工具。它通过用户界面&#xff08…

mysql的事务控制和数据库的备份和恢复

事务控制语句 行锁和死锁 行锁 两个客户端同时对同一索引行进行操作 客户端1正常运行 客户端2想修改&#xff0c;被锁行 除非将事务提交才能继续运行 死锁 客户端1删除第5行 客户端2设置第1行为排他锁 客户端1删除行1被锁 客户端2更新行5被锁 如何避免死锁 mysql的备份和还…

Tengine:Nginx二次开发-高性能进化

前言&#xff1a;在当今的互联网时代&#xff0c;Web 服务器的性能和稳定性对于网站的成功至关重要。Nginx 以其高性能和可扩展性而闻名&#xff0c;但有时候&#xff0c;我们需要更多的特性来满足特定的业务需求。Tengine&#xff0c;作为一个由淘宝网发起的 Nginx 二次开发版…

RK3588, FFmpeg 拉流 RTSP, mpp 硬解码转RGB

RK3588 ,基于FFmpeg, 拉取RTSP,使用 mpp 实现硬解码. ⚡️ 传送 ➡️ Ubuntu x64 架构, 交叉编译aarch64 FFmpeg mppRK3588, FFmpeg 拉流 RTSP, mpp 硬解码转RGBRk3588 FFmpeg 拉流 RTSP, 硬解码转RGBRK3588 , mpp硬编码yuv, 保存MP4视频文件.

Windows 下 Anaconda的安装与配置 GPU 版

给之前的电脑安一下深度学习环境 判断是否有NVIDIA GPU Ctrl Shift Esc 打开任务管理器 带此字眼表示有 NVIDIA GPU 安装Anaconda anaconda 打开邮箱会看到下载链接 这里建议修改为其他盘,要不然下载的包和创建的环境都在C盘&#xff0c;占用空间 三个都打钩 取…

flask flask-socketio创建一个网页聊天应用

应用所需环境&#xff1a; python 3.11.11 其他 只需要通过这个命令即可 pip install flask3.1.0 Flask-SocketIO5.4.1 -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple 最好是用conda创建一个新的虚拟环境来验证 完整的pip list如下 Package Version ----…

STM32 水质水位检测项目(硬件架构)及(软件架构)

硬件选型 水位测量模块 TDS采集模块 外置ADC模块&#xff08;ADS1115&#xff09; 水位测量模块使用方法 水位测量原理 压力传感器&#xff1a;水越深压力越大 P ρgh Fps Fρgh*s P大气压 水位测量传感器本质上是一个压力测量传感器。压力的值和传感器产生的电压值是线…

服务器数据恢复—RAIDZ离线硬盘数超过热备盘数导致阵列崩溃的数据恢复案例

服务器存储数据恢复环境&#xff1a; ZFS Storage 7320存储阵列中有32块硬盘。32块硬盘分为4组&#xff0c;每组8块硬盘&#xff0c;共组建了3组RAIDZ&#xff0c;每组raid都配置了热备盘。 服务器存储故障&#xff1a; 服务器存储运行过程中突然崩溃&#xff0c;排除人为误操…

llama2中的model.py中的结构示意图

参考文章&#xff1a;https://zhuanlan.zhihu.com/p/679640407

开放词汇目标检测(Open-Vocabulary Object Detection, OVOD)综述

定义 开放词汇目标检测&#xff08;Open-Vocabulary Object Detection, OVOD&#xff09;是一种目标检测任务&#xff0c;旨在检测和识别那些未在训练集中明确标注的物体类别。传统的目标检测模型通常只能识别有限数量的预定义类别&#xff0c;而OVOD模型则具有识别“开放词汇…

Vue与React:前端框架的巅峰对决

文章目录 一、引言&#xff08;一&#xff09;前端框架发展现状简述 二、Vue 与 React 框架概述&#xff08;一&#xff09;Vue.js 简介&#xff08;二&#xff09;React.js 简介 三、开发效率对比&#xff08;一&#xff09;Vue 开发效率分析&#xff08;二&#xff09;React …

3分钟读懂数据分析的流程是什么

数据分析是基于商业目的&#xff0c;有目的地进行收集、整理、加工和分析数据&#xff0c;提炼出有价值的 信息的一个过程。整个过程大致可分为五个阶段&#xff0c;具体如下图所示。 1.明确目的和思路 在开展数据分析之前&#xff0c;我们必须要搞清楚几个问题&#xff0c;比…

词嵌入(Word Embedding):自然语言处理的基石

目录 ​编辑 词嵌入&#xff08;Word Embedding&#xff09;&#xff1a;自然语言处理的基石 引言 词嵌入的基本概念 词嵌入的主要方法 1. Word2Vec 2. GloVe 3. FastText 4. ELMo 5. BERT 词嵌入的应用场景 词嵌入的研究进展 结论 词嵌入&#xff08;Word Embedd…

AutoSarOS中调度表的概念与源代码解析

--------AutoSarOS调度表的概念 一、AutoSarOS 是什么以及调度表的重要性 AutoSar(Automotive Open System Architecture)是汽车行业的一个开放式软件架构标准哦。它就像是一种大家都遵循的规则,能让不同的软件供应商一起合作开发汽车软件,这样软件就能被重复使用,开发效…

半连接转内连接 | OceanBase SQL 查询改写

查询优化器是关系型数据库系统的核心模块&#xff0c;是数据库内核开发的重点和难点&#xff0c;也是衡量整个数据库系统成熟度的“试金石”。为了帮助大家更好地理解 OceanBase 查询优化器&#xff0c;我们撰写了查询改写系列文章&#xff0c;带大家更好地掌握查询改写的精髓&…

android opencv导入进行编译

1、直接新建module进行导入&#xff0c;选择opencv的sdk 导入module模式&#xff0c;选择下载好的sdk&#xff0c;修改module name为OpenCV490。 有报错直接解决报错&#xff0c;没报错直接运行成功。 2、解决错误&#xff0c;同步成功 一般报错是gradle版本问题较多。我的报…

通过阿里云 Milvus 与 PAI 搭建高效的检索增强对话系统

背景介绍 阿里云向量检索服务Milvus版&#xff08;简称阿里云Milvus&#xff09;是一款云上全托管服务&#xff0c;确保了了与开源Milvus的100%兼容性&#xff0c;并支持无缝迁移。在开源版本的基础上增强了可扩展性&#xff0c;能提供大规模 AI 向量数据的相似性检索服务。相…

【批量生成WORD和PDF文件】根据表格内容和模板文件批量创建word文件,一次性生成多个word文档和批量创建PDF文件

如何按照Word模板和表格的数据快速制作5000个word文档 &#xff1f; 在与客户的合作的中需要创建大量的合同&#xff0c;这些合同的模板大概都是一致的&#xff0c;是不是每次我们都需要填充不一样的数据来完成&#xff1f; 今天用表格数据完成合同模板的填充&#xff0c;批量…

Windows11 安装 Ubuntu-20.04,同时安装配置 zsh shell,配置 git 别名(alias),大大提高开发效率

背景&#xff1a;家里配置了一台 Windows 电脑&#xff0c;有时候需要用到 vscode 开发测试一些代码&#xff0c;在使用过程中发现原生 windows 敲代码不是很友好&#xff0c;于是想到配置 wsl&#xff0c;安装 Ubuntu&#xff0c;并安装配置 zsh shell&#xff0c;同时配置 gi…

鸿蒙心路旅程:HarmonyOS NEXT 心路旅程:技术、成长与未来

HarmonyOS NEXT 心路旅程&#xff1a;技术、成长与未来 技术的浪潮中&#xff0c;总有一些瞬间让人感到心潮澎湃。作为一名HarmonyOS NEXT开发者&#xff0c;我有幸成为这个时代科技创新的一部分。从最初的接触到深入学习、开发&#xff0c;以及如今规划未来的职业方向&#x…