【Spring】SpringBoot 统一功能处理

在这里插入图片描述

文章目录

  • 前言
  • 1. 拦截器
    • 1.1 什么是拦截器
    • 1.2 拦截器的使用
      • 1.2.1 自定义拦截器
      • 1.2.2 注册配置拦截器
    • 1.3 拦截器详解
      • 1.3.1 拦截路径
      • 1.3.2 拦截器执行流程
      • 1.3.3 适配器模式
  • 2. 统一数据返回格式
  • 3. 统一异常处理

前言

在日常使用 Spring 框架进行开发的时候,对于一些板块来说,可能需要实现一个相同的功能,这个功能可以是验证你的登录信息,也可以是其他的,但是由于各个板块实现这个功能的代码逻辑都是相同的,如果一个板块一个板块进行添加的话,开发效率就会很低,所以 Spring 也想到了这点,为我们程序员提供了 SpringBoot 统一功能处理的方法实现,我们是可以直接使用的。这篇文章我将带大家一起学习 SpringBoot 统一功能的处理。

1. 拦截器

正常的判断用户是否登录的逻辑就是通过 session 来判断,对于一些网站来说,很多的功能都是需要用户进行登录之后才可以使用的,如果此时通过 session 判断出来用户处于未登录状态的话,咱们的服务器会强制用户进行登录,通过代码来显示就是这样的:

//检验用户是否登录
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("userInfo") == null) {
    return "您未登录,请登录后再试试该功能吧";
}

我们想要在哪个功能前判断用户的登录信息,就需要在该功能的模块中添加上面这些代码,如果需要添加的功能较少还好,如果很多,那么就需要花费很多的时间,那么有人就说了:我是否可以将这些代码封装成函数,然后哪个模块需要使用只需要调用这些函数就可以了呢?可以是可以,但是使用函数封装代码还是需要在原代码的基础上调用这个函数,并且显得也不是那么优雅。那么是否有方法既不需要更改原代码,也可以使得我们写的代码很优雅呢?SpringBoot 为我们提供了一种功能——拦截器。

1.1 什么是拦截器

在 Spring Boot 中,拦截器是一种用于在处理请求之前或之后执行特定操作的组件。拦截器通常用于实现一些通用的功能,比如权限验证、日志记录等。拦截器可以拦截通过Controller的请求,并在请求处理前后执行特定的操作。

拦截器的思想正好符合我们执行其他功能之前进行身份验证验证,并且不仅在方法执行之前拦截器可以起作用,方法执行之后。我们的拦截器也可以起到作用。

在这里插入图片描述

1.2 拦截器的使用

拦截器的使用分为两个步骤:

  1. 定义拦截器
  2. 注册配置拦截器

1.2.1 自定义拦截器

我们自定义的拦截器需要实现 HandlerInterceptor 接口,并且重写这个接口中的方法。

package com.example.springbootbook2.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("目标方法执行前执行...");
        HttpSession session = request.getSession(false);
        if (session == null || session.getAttribute("userInfo") == null) {
        	response.setStatus(401);
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("目标方法执行后执行...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("视图渲染完毕之后执行,最后执行...");
    }
}

  • preHandle() 方法是在目标方法执行之前执行的,返回 true,继续执行后面的代码;返回 false,中断后续的操作
  • postHandle() 方法是在目标方法执行之后执行的
  • afterCompletion() 方法是在视图渲染之后才执行的,它还在 postHandle() 方法之后执行,并且现在因为前后端分离,我们后端基本上接触不到视图的渲染,所以这个方法使用的较少

1.2.2 注册配置拦截器

注册配置拦截器需要实现 WebMvcConfiguer 接口,并实现 addInterceptors 方法。

package com.example.springbootbook2.config;

import com.example.springbootbook2.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")  //指定路径配置拦截器
                .excludePathPatterns("/user/login");  //指定路径不配置拦截器
    }
}

在添加拦截器进行身份校验之前,我们可以直接通过对应的 url 访问到指定功能页面。

在这里插入图片描述

而在我们添加拦截器之后,再看是否能直接访问某些功能。

在这里插入图片描述
在这里插入图片描述

我们启动添加了拦截器之后的代码之后,点击刷新就发现不能够直接访问到某些功能了,再搭配着前端我们就可以实现强制登录的功能了。

1.3 拦截器详解

拦截器的⼊⻔程序完成之后,接下来我们来介绍拦截器的使⽤细节。拦截器的使⽤细节我们主要介绍两个部分:

  1. 拦截器的拦截路径配置
  2. 拦截器实现原理

1.3.1 拦截路径

拦截路径是指我们定义的这个拦截器,对哪些请求生效,我们在注册配置拦截器的时候,通过 addPathPatterns() 方法指定要拦截哪些 HTTP 请求,也可以通过 excludePathPatterns() 方法指定不拦截哪些请求,上面我们的 /** 表示拦截所有的 HTTP 请求,除了可以设置拦截所有请求外,还有一些其他的拦截设置:

拦截路径含义举例
/*⼀级路径能匹配/user,/book,/login,不能匹配 /user/login
/**任意级路径能匹配/user,/user/login,/user/reg
/book/*/book下的⼀级路径能匹配/book/addBook,不能匹配/book/addBook/1,/book
/book/**/book下的任意级路径能匹配/book,/book/addBook,/book/addBook/2,不能匹配/user/login

这些拦截规则可以拦截此项⽬中的使⽤ URL,包括静态⽂件(图⽚⽂件、JS、和 CSS 等⽂件)。

知道了如何配置拦截路径之后,我们就可以解决网页上身份验证的问题了。因为 /** 会拦截所有的请求,包括前端页面请求,所以我们需要将前端页面请求排除在拦截之外。

如果我们不讲前端页面请求在外的话机会出现这种情况:

在这里插入图片描述
然后我们将前端页面请求不添加拦截器的话,就可以实现完整的身份校验强制登录功能了。

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    private List<String> excludePath = Arrays.asList("/user/login",
            "/css/**",
            "/js/**",
            "/pic/**",
            "/**/*.html");  // /**/*html中的/**表示所有路径下的所有以html结尾的文件 * 表示通配符
            
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(excludePath);
    }
}

当我们未登录,然后访问其他功能的话,就会强制跳转到登录页面:

在这里插入图片描述

1.3.2 拦截器执行流程

正常的调用顺序是这样的:

在这里插入图片描述
有了拦截器之后,会在调⽤ Controller 之前进⾏相应的业务处理,执⾏的流程如下图:

在这里插入图片描述

  1. 当我们添加拦截器之后,在执行 Controller 方法之前,请求会先被拦截器拦截,执行 preHandle() 方法,这个方法会返回一个布尔类型的值,如果返回的是 true,那么会继续执行后面的操作;如果返回的是 false,则不会执行后面的操作
  2. Controller 当中的方法执行完毕之后,会继续执行 postHandle() 方法以及 afterHandle() 方法,执行完毕之后,返回给浏览器响应数据。

在源码中的 DispatcherServlet 类中的 doDispatch 方法中可以看到这三个方法的执行流程:

在这里插入图片描述

1.3.3 适配器模式

在拦截器执行的过程中还使用了适配器模式:

在这里插入图片描述
适配器模式(Adapter Pattern)在计算机编程中是一种常用的设计模式,主要用于解决两个不兼容的类之间的接口匹配问题。通过将一个类的接口转换成客户端所期望的另一种接口,原本因为接口不匹配而无法一起工作的两个类现在可以一起工作。

适配器模式的优点在于它能够使原本由于接口不兼容而无法一起工作的类一起工作,提高了系统的灵活性和可扩展性。同时,它也能够减少代码的重复性,因为多个源可以共享同一个适配器。

HandlerAdapter 主要⽤于⽀持不同类型的处理器(如 Controller、HttpRequestHandler 或者
Servlet 等),让它们能够适配统⼀的请求处理流程。这样,SpringMVC可以通过⼀个统⼀的接⼝
来处理来⾃各种处理器的请求。

在这里插入图片描述
本来 target 和 adaptee 是两个无法正常对接的事物,但是通过适配器 adapter,这两者之间就可以进行对接,也就类似于下面这个情况:

在这里插入图片描述
适配器模式⻆⾊:

  • Target:⽬标接口(可以是抽象类或接口)客户希望直接⽤的接口
  • Adaptee:适配者,但是与Target不兼容
  • Adapter:适配器类,此模式的核⼼。通过继承或者引⽤适配者的对象,把适配者转为⽬标接⼝
  • client:需要使⽤适配器的对象

前⾯学习的 slf4j 就使⽤了适配器模式,slf4j 提供了⼀系列打印⽇志的 api,底层调⽤的是 log4j 或者logback 来打⽇志,我们作为调⽤者,只需要调⽤ slf4j 的 api 就⾏了。

/**
* slf4j接⼝
*/
interface Slf4jApi{
	void log(String message);
}

/**
* log4j 接⼝
*/
class Log4j{
	void log4jLog(String message){
		System.out.println("Log4j打印:"+message);
	}
}

/**
* slf4j和log4j适配器
*/
class Slf4jLog4JAdapter implements Slf4jApi{
	private Log4j log4j;
	public Slf4jLog4JAdapter(Log4j log4j) {
		this.log4j = log4j;
	}
	@Override
	public void log(String message) {
		log4j.log4jLog(message);
	}
}

/**
* 客⼾端调⽤
*/
public class Slf4jDemo {
	public static void main(String[] args) {
		Slf4jApi slf4jApi = new Slf4jLog4JAdapter(new Log4j());
		slf4jApi.log("使⽤slf4j打印⽇志");
	}
}

可以看出,我们不需要改变 log4j 的api,只需要通过适配器转换下,就可以更换⽇志框架,保障系统的平稳运行。

⼀般来说,适配器模式可以看作⼀种"补偿模式",⽤来补救设计上的缺陷。应⽤这种模式算是"⽆奈之举",如果在设计初期,我们就能协调规避接⼝不兼容的问题,就不需要使⽤适配器模式了。

所以适配器模式更多的应⽤场景主要是对正在运⾏的代码进⾏改造,并且希望可以复⽤原有代码实现新的功能.。⽐如版本升级等。

2. 统一数据返回格式

如果我们完成了一个项目的开发,但是这时候,我们突然觉得后端的各个功能的返回值返回的信息不够全面,我们需要补充一些返回信息,那么这时候就意味着所有方法的返回值都需要做出修改,这也是一个不小的工作量。这时 SpringBot 又为我们提供了解决方法——统一数据返回格式。

SpringBoot 统一数据返回格式会在各个方法进行 return 返回值之前插入一些代码逻辑,从而达到改变返回值的功能。

统一的数据返回格式使用 @ControllerAdviceResponseBodyAdvice 的方式实现。ControllerAdvice 表示控制器通知类。

我们先定义一个统一的返回类型:

public enum ResultCode {
    SUCCESS(0),
    FAIL(-1),
    UNLOGIN(-2);

    //0-成功  -1 失败  -2 未登录
    private int code;

    ResultCode(int code) {
        this.code = code;
    }


    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }
}
@Data
public class Result<T> {
    /**
     * 业务状态码
     */
    private ResultCode code;  //0-成功  -1 失败  -2 未登录
    /**
     * 错误信息
     */
    private String errMsg;
    /**
     * 数据
     */
    private T data;

    public static <T> Result<T> success(T data){
        Result result = new Result();
        result.setCode(ResultCode.SUCCESS);
        result.setErrMsg("");
        result.setData(data);
        return result;
    }
    public static <T> Result<T> fail(String errMsg){
        Result result = new Result();
        result.setCode(ResultCode.FAIL);
        result.setErrMsg(errMsg);
        result.setData(null);
        return result;
    }
    public static <T> Result<T> fail(String errMsg,Object data){
        Result result = new Result();
        result.setCode(ResultCode.FAIL);
        result.setErrMsg(errMsg);
        result.setData(data);
        return result;
    }
    public static <T> Result<T> unlogin(){
        Result result = new Result();
        result.setCode(ResultCode.UNLOGIN);
        result.setErrMsg("用户未登录");
        result.setData(null);
        return result;
    }

}
package com.example.springbootbook2.config;

import com.example.springbootbook2.model.Result;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return Result.success(body);
    }
}

继承 ResponseBodyAdvice 接口后,需要实现该接口下的 supports 方法和 beforeBodyWrite 方法,supports 方法只需要更改返回值为 true 就可以了,表示是否要执行 beforeBodyWrite 方法,返回 true 表示执行,false 表示不执行,beforeBodyWrite 方法中的 body 参数就是我们原方法的返回值。

当我们关闭拦截器,访问图书列表页之后,就发现我们的返回类型发生了变化:

在这里插入图片描述
但是这个统一数据返回格式也存在问题,当我们的返回值为 String 类型的话机会出现错误:

在这里插入图片描述
在这里插入图片描述
这是为什么呢?SpringMVC默认会注册⼀些⾃带的 HttpMessageConverter (从先后顺序排列分别为
ByteArrayHttpMessageConverter ,StringHttpMessageConverter , SourceHttpMessageConverter ,AllEncompassingFormHttpMessageConverter )
在这里插入图片描述
其中 AllEncompassingFormHttpMessageConverter 会根据项⽬依赖情况添加对应的
HttpMessageConverter

在这里插入图片描述

在依赖中引⼊jackson包后,容器会把 MappingJackson2HttpMessageConverter ⾃动注册到
messageConverters 链的末尾。Spring会根据返回的数据类型,从 messageConverters 链选择合适的 HttpMessageConverter。当返回的数据是⾮字符串时,使⽤的MappingJackson2HttpMessageConverter 写⼊返回对象。当返回的数据是字符串时, StringHttpMessageConverter 会先被遍历到,这时会认为
StringHttpMessageConverter 可以使用。

在这里插入图片描述
在这里插入图片描述
然⽽⼦类 StringHttpMessageConverter 的addDefaultHeaders⽅法定义接收参数为String,此
时t为Result类型,所以出现类型不匹配"Result cannot be cast to java.lang.String"的异常。

那么如何解决返回类型为 String 类型的问题呢?如果返回结果为String类型, 使⽤SpringBoot内置提供的Jackson来实现信息的序列化。

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    @Autowired
    private ObjectMapper objectMapper;
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof String) {
            return objectMapper.writeValueAsString(Result.success(body));
        }else if (body instanceof Result) {
            return body;
        }else {
            return Result.success(body);
        }
    }
}
  • @SneakyThrows 的主要目的是解决 Java 的异常处理问题。当我们在代码中抛出一个异常时,如果这个异常被包裹在一个方法中,并且这个方法没有 throws 关键字来声明会抛出这个异常,那么编译器会报错。通过使用 @SneakyThrows,你可以告诉编译器:“我知道这个方法可能会抛出异常,但我保证在 catch 块中处理它。” 这样编译器就不会报错了。

通过这个处理,当返回的数据类型为 String 的时候就不会出现错误了。

在这里插入图片描述
统一数据返回格式的优点:

  1. ⽅便前端程序员更好的接收和解析后端数据接口返回的数据
  2. 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就可以了,因为所有接口都是这样返回的
  3. 有利于项目统⼀数据的维护和修改
  4. 有利于后端技术部⻔的统⼀规范的标准制定,不会出现稀奇古怪的返回内容

3. 统一异常处理

当我们的程序中出现异常的时候,我们需要解决这些异常,因为前面做了统一数据返回格式的处理,所以这里的异常也可以进行统一的处理。

统⼀异常处理使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表⽰控制器通知类, @ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执行某个通知,也就是执⾏某个⽅法事件。

package com.example.springbootbook2.config;

import com.example.springbootbook2.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@Slf4j
@ResponseBody  //因为返回的数据都不是视图类型,所以加上这个注解防止出现问题
public class ErrorHandler {
    @ExceptionHandler
    public Result<String> exception(Exception e) {
        log.error("发生异常:e{}",e);
        return Result.fail("内部异常");
    }

    @ExceptionHandler
    public Result<String> exception(NullPointerException e) {
        log.error("发生异常:e{}",e);
        return Result.fail("NullPointerException异常,请联系管理员");
    }

    @ExceptionHandler
    public Result<String> exception(ArithmeticException e) {
        log.error("发生异常:e{}",e);
        return Result.fail("ArithmeticException异常,请联系管理员");
    }
}

@Controller
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/t1")
    public Integer test1() {
        return 10/0;
    }
}

在这里插入图片描述

这个 Exception 和 ArithmeticException 的先后顺序可以不考虑,这个不会因为 Exception 在前面捕获就报的 Exception 异常,而是会根据自己出现的最接近的异常来捕获。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么是Java泛型?泛型在Java中应用场景

目录 一、什么是Java泛型 二、泛型类 三、泛型接口 四、泛型方法 一、什么是Java泛型 Java泛型是一种在编译时进行类型检查和类型安全的机制。它允许编写能够操作多种类型的代码&#xff0c;而不需要进行类型转换或使用Object类型。通过在定义类、接口或方法时使用泛型参数…

Arduino快速上手esp8266方案开发

认识ESP8266 ESP8266 是 Espressif Systems 生产的 Wi-Fi 片上系统 (SoC)。它非常适合物联网和家庭自动化项目&#xff0c;目前有非常高的市场普及率&#xff0c;还有更加高端的同时支持wifi和蓝牙的双核心芯片ESP32&#xff0c;可以在乐鑫官网查看完整的芯片列表。 ESP8266芯…

克服大模型(LLM)部署障碍,全面理解LLM当前状态

近日&#xff0c;CMU Catalyst 团队推出了一篇关于高效 LLM 推理的综述&#xff0c;覆盖了 300 余篇相关论文&#xff0c;从 MLSys 的研究视角介绍了算法创新和系统优化两个方面的相关进展。 在人工智能&#xff08;AI&#xff09;的快速发展背景下&#xff0c;大语言模型&…

element中el-cascader级联选择器只有最后一级可以多选

文章目录 一、前言二、实现2.1、设置popper-class和multiple2.2、设置样式 三、最后 一、前言 element-ui中el-cascader级联选择器只有最后一级可以多选&#xff0c;其它级只有展开子节点的功能&#xff0c;如下图所示&#xff1a; 可以观察到最后一级的li节点上没有属性aria-…

Python爬虫—requests模块简单应用

Python爬虫—requests模块简介 requests的作用与安装 作用&#xff1a;发送网络请求&#xff0c;返回响应数据 安装&#xff1a;pip install requests requests模块发送简单的get请求、获取响应 需求&#xff1a;通过requests向百度首页发送请求&#xff0c;获取百度首页的…

MATLAB R2023b for Mac 中文

MATLAB R2023b 是 MathWorks 发布的最新版本的 MATLAB&#xff0c;适用于进行算法开发、数据可视化、数据分析以及数值计算等任务的工程师和科学家。它包含了一系列新增功能和改进&#xff0c;如改进了数据导入工具&#xff0c;增加了对数据帧和表格对象的支持&#xff0c;增强…

pr怎么剪掉不要的部分?

在我们的日常工作中&#xff0c;剪视频的时候常常会需要把某个视频中我们不想要的地方剪掉&#xff0c;有的时候是一段&#xff0c;也有可能是好几段。但具体应该怎么样把不要的视频剪掉呢&#xff1f;其实&#xff0c;用pr软件就可以啦&#xff01;那么&#xff0c;pr怎么剪掉…

微信小程序开发WebSocket通讯

官方文档说明&#xff1a;入口 WebSocket连接的链接只支持wss加密方式&#xff0c;且只能用域名的方式 该域名还要在微信公众平台的小程序中登记才能使用&#xff0c;开发->开发管理->服务器域名->修改 该域名要和https使用的一致 以域名地址&#xff1a;dtu.aab…

2024年第02周农产品价格报告

一、摘要 农产品价格监测主要涉及对畜禽类产品、水产品、蔬菜类产品、水果类产品的价格&#xff0c;以周为单位&#xff0c;进行变化情况的数据监测。其中&#xff0c;蔬菜类产品共18种&#xff0c;分别为大白菜、西红柿、黄瓜、青椒、芹菜、土豆、白萝卜、茄子、豆角、胡萝卜…

华媒舍:高效率的新闻资讯新闻媒体宣发套餐内容推广计划方案

怎样让自己的新闻资讯可以被大众孰知&#xff0c;变成了每一个新闻媒体宣发者一同存在的困难。下面我们就给大家介绍一套高效率的新闻资讯新闻媒体宣发套餐内容推广计划方案&#xff0c;致力于帮助新闻媒体宣发者提升宣发高效率&#xff0c;提高新闻资讯的传播性。 1.新闻媒体宣…

如何通过内网穿透实现公网访问Portainer管理监控Docker容器

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风…

GoZero微服务个人探究之路(二)Go-Zero官方api demo示例探究

官方文档api-demo教程部分网址如下&#xff1a; api demo 代码生成 | go-zero Documentation 官方demo的架构如下&#xff1a; 编辑 etc包下&#xff1a; demo-api.yaml 编辑服务名称&#xff1a;demo-apiHOST地址&#xff1a;0.0.0.0监听所有可用网络接口Port地址&#…

XSKY助力首个云原生、分布式、全栈国产化银行核心系统投产上线

近日&#xff0c;。该项目是业内首个实际投产的云原生、分布式、全栈国产化的银行核心业务系统&#xff0c;是金融科技领域突破关键核心技术应用的重大实践。 在杭州银行的新一代核心系统中&#xff0c;XSKY星辰天合具备天合翔宇“一池多芯”技术的对象存储支持了核心业务模块…

每日一题 82. 删除排序链表中的重复元素 II(中等,链表)

和昨天差不多&#xff0c;今天的是把所有重复数字的节点都删除&#xff08;昨天留了一个&#xff09; 显然当我们发现重复数字时&#xff0c;需要重复的第一个数字的前一个节点才能把重复数字删完&#xff0c;所有在while循环中我们每次判断 t.next 和 t.next.next 的值是否重复…

AI模型理解误区:微调垂直行业-VS-企业专属知识库或AI助理

概述 企业定制私有化大模型的区别&#xff0c;分为训练大模型和调用大模型两种方向&#xff0c;以及企业自己的智能客服的实现方法。 - 企业定制的私有化大模型与一般的大模型不同&#xff0c;需要高成本训练。- 企业可以选择调用已经训练好的大模型来应用。- 企业可以使用向量…

Zabbix监控(1)

目录 一.什么是zabbix Zabbix 组件&#xff1a; 主动模式&#xff1a; 被动模式&#xff1a; Zabbix 工作原理&#xff1a; zabbix 监控原理&#xff1a; 二.Zabbix 6.0 部署 先安装nginx&#xff0c;php&#xff08;yum源安装&#xff09;&#xff1a; 安装nginx&…

【面试突击】Java内存模型实战

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术 的推送 发送 资料 可领取 深入理…

python的包argparse介绍

argparse是一个用来解析命令行参数的 Python 库&#xff0c;它是 Python 标准库的一部分。 1、未使用argparse: import math# 计算圆柱体的体积 def cal_vol(radius,height):vol math.pi * pow(radius,2) * heightreturn vol if __name____main__:print(cal_vol(2,4))2、使用…

Model:字符串列表模型QStringListModel

一、QStringListModel &#xff08;1&#xff09;功能&#xff1a;处理字符串列表的数据模型&#xff0c;可作为QListView的数据模型&#xff0c;在界面上显示和编辑字符串列表。 二、QStringListModel 类中的函数 1)、 QStringListModel(QObject *parent Q_NULLPTR) //构造函…

FairyGUI Day 1 导入FairyGUI

FairyGUI Unity3d引擎版本&#xff1a;Uinty3d 20233.2.3f1 1、从资产商店中将FairyGUI购入我的资产中&#xff0c;目前是免费的。 2、从我的资产中将FairyGUI导入到当前项目中。 3、我遇到的问题&#xff0c;我的Assets下有两个文件夹分别是Resources和Scenes&#xff0c;导…