Web后端开发:登录认证案例

news2025/1/21 1:01:42

登录功能

需求分析

在这里插入图片描述
  在登录界面中,输入用户的用户名以及密码,然后点击 “登录” ,服务端判断用户输入的用户名和密码是否都正确。如果正确,则返回成功结果,前端跳转至系统首页面;否则报错,停留在登录界面。

接口文档

请求路径:/login
请求方式:POST
接口描述:该接口用于员工登录Tlias智能学习辅助系统,登录完毕后,系统下发JWT令牌。

请求参数参数格式:application/json
请求数据样例:
	{
	"username": "jinyong",
	"password": "123456"
	}

响应数据参数格式:application/json
响应数据样例:
	{
	"code": 1,
	"msg": "success",
	"data":
		"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo"
	}

请求参数参数说明:
在这里插入图片描述
.
请求参数参数说明:
在这里插入图片描述

思路分析

在这里插入图片描述

  登录服务端的核心逻辑就是:接收前端请求传递的用户名和密码 ,然后再根据用户名和密码查询用户信息,如果用户信息存在,则说明用户输入的用户名和密码正确。如果查询到的用户不存在,则说明用户输入的用户名和密码错误。

功能开发

LoginController

@Slf4j
@RestController
public class LoginController {

    @Autowired
    private EmpService empService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp){
        log.info("员工登录:{}",emp);

        Emp e = empService.login(emp);
        return e != null ? Result.success():Result.error("用户名或密码错误");
    }
}

EmpService

// 用户登录
Emp login(Emp emp);

EmpServiceImpl

@Override
public Emp login(Emp emp) {
    //调用dao层功能:登录
    Emp loginEmp = empMapper.getByUsernameAndPassword(emp);

    //返回查询结果给Controller
    return loginEmp;
}

EmpMapper

@Select("select id, username, password, name, gender, image,job, entrydate, dept_id, create_time, update_time " +
            "from empf  where username=#{username} and password =#{password}")
Emp getByUsernameAndPassword(Emp emp);

功能测试

在这里插入图片描述

登录校验

会话技术

  在web开发当中,会话指的是浏览器与服务器之间的一次连接。
  需要注意的是:会话和浏览器是关联的。
  会话跟踪:是一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。

会话跟踪技术有两种:
	Cookie(客户端会话跟踪技术),即数据存储在客户端浏览器当中
	Session(服务端会话跟踪技术),即数据存储在储在服务端

传统的会话跟踪技术,在现在的开发当中存在很多的问题。 为了解决这些问题,在现在开发中基本上都会采用第三种方案,通过令牌技术来进行会话跟踪。

JWT令牌

JWT介绍

  JWT全称:JSON Web Token,定义了一种简洁的、自包含的格式,用于在通信双方以 json 数据格式安全的传输信息。

JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)
	第一部分:Header(头), 记录令牌类型、签名算法等。 
		例如:{"alg":"HS256","type":"JWT"}
	第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 
		例如:{"id":"1","username":"Tom"}
	第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

JWT令牌最典型的应用场景就是登录认证:
  1. 在浏览器发起登录请求,此时会访问登录接口,如果登录成功,则会生成一个jwt令牌,并将生成的 jwt令牌返回给前端。
  2. 前端拿到jwt令牌之后,会将jwt令牌存储起来。在后续的每一次请求中都会将jwt令牌携带到服务端。
  3. 服务端统一拦截请求之后,先判断请求有没有携带令牌,如果没有则直接拒绝访问;如果有,还需要校验一下令牌是否是有效,有效则直接放行进行请求的处理。

在JWT登录认证整个流程当中涉及到两步操作:
	1. 在登录成功之后,生成令牌。
	2. 每一次请求当中,要接收令牌并对令牌进行校验。

生成jwt令牌

  JWT的依赖

<!-- JWT依赖 -->
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt</artifactId>
	<version>0.9.1</version>
</dependency>

  生成JWT代码

@Test
public void genJwt(){
	Map<String,Object> claims = new HashMap<>();
	claims.put("id",1);
	claims.put("username","Tom");
	
	String jwt = Jwts.builder()
		.setClaims(claims) //自定义内容(载荷)
		.signWith(SignatureAlgorithm.HS256, "itheima") //签名算法
		.setExpiration(new Date(System.currentTimeMillis() + 24*3600*1000)) //有效期
		.compact();
	System.out.println(jwt);
}

校验jwt令牌

  解析生成的令牌

@Test
public void parseJwt(){
	Claims claims = Jwts.parser()
	//指定签名密钥(必须保证和生成令牌时使用相同的签名密钥)
	.setSigningKey("itheima")
	.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71UqLXDdLyipptLgxBUg_mSuGJtXtBk")
	.getBody();
	System.out.println(claims);
}
在使用JWT令牌时需要注意:
	JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。
	如果JWT令牌解析校验时报错,则说明JWT令牌被篡改或失效了,令牌非法。

登录下发令牌

通过JWT令牌技术来跟踪会话,主要是两步操作:
	1. 生成令牌
	2. 校验令牌	

JWT令牌怎么返回给前端呢?主要看接口文档中关于登录接口的描述的响应数据:
响应数据参数格式:application/json
响应数据样例:
	{
		"code": 1,
		"msg": "success",
		"data":"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo"
	}

响应数据参数说明:
在这里插入图片描述

过滤器Filter

  怎么判断统一拦截到所有的请求校验令牌的有效性呢?有两种解决方案:1. Filter过滤器、2. Interceptor拦截器

  Filter过滤器,是 JavaWeb三大组件(Servlet、Filter、Listener)之一。过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。使用了过滤器之后,要想访问web服务器上的资源,必须先经过滤器,过滤器处理完毕之后,才可以访问对应的资源。过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。

Filter快速入门

过滤器的基本使用操作:
	第1步,定义过滤器 :1.定义一个类,实现 Filter 接口,并重写其所有方法。
	第2步,配置过滤器:Filter类上加 @WebFilter 注解,配置拦截资源的路径。
					  引导类上加@ServletComponentScan 开启Servlet组件支持。

定义过滤器

//定义一个类,实现一个标准的Filter过滤器的接口
public class DemoFilter implements Filter {
	@Override //初始化方法, 只调用一次
	public void init(FilterConfig filterConfig) throws
		ServletException {
		System.out.println("init 初始化方法执行了");
	}
	
	@Override //拦截到请求之后调用, 调用多次
	public void doFilter(ServletRequest request, ServletResponse
		response, FilterChain chain) throws IOException, ServletException {
		System.out.println("Demo 拦截到了请求...放行前逻辑");
		//放行
		chain.doFilter(request,response);
	}
	
	@Override //销毁方法, 只调用一次
	public void destroy() {
		System.out.println("destroy 销毁方法执行了");
	}
}

Filter的配置

@WebFilter(urlPatterns = "/*") //配置过滤器要拦截的请求路径( /* 表示拦截浏览器的所有请求 )
public class DemoFilter implements Filter {
	@Override //初始化方法, 只调用一次
	public void init(FilterConfig filterConfig) throws
		ServletException {
		System.out.println("init 初始化方法执行了");
	}
	
	@Override //拦截到请求之后调用, 调用多次
	public void doFilter(ServletRequest request, ServletResponse
		response, FilterChain chain) throws IOException, ServletException {
		System.out.println("Demo 拦截到了请求...放行前逻辑");
		//放行
		chain.doFilter(request,response);
	}
	
	@Override //销毁方法, 只调用一次
	public void destroy() {
		System.out.println("destroy 销毁方法执行了");
	}
}

  在Filter类上面加了@WebFilter注解之后,还需要在启动类上面加上一个注解@ServletComponentScan,通过这个@ServletComponentScan注解来开启SpringBoot项目对于Servlet组件的支持。

@ServletComponentScan
@SpringBootApplication
public class SpringbootWebExampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebExampleApplication.class, args);
    }

}

Filter详解

过滤器的执行流程

在这里插入图片描述
  过滤器拦截到请求后,如果要继续访问后面的web资源,则需要执行放行操作,即调用 FilterChain对象当中的doFilter()方法。在放行后访问完 web 资源之后还会回到过滤器当中,回到过滤器之后如有需求还可以执行放行之后的逻辑,放行之后的逻辑我们写在doFilter()这行代码之后。

@WebFilter(urlPatterns = "/*") //配置过滤器要拦截的请求路径( /* 表示拦截浏览器的所有请求 )
public class DemoFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        System.out.println("init 初始化方法执行了");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Demo 拦截到了请求...放行前逻辑");

        //放行
        filterChain.doFilter(servletRequest, servletResponse);

		System.out.println("DemoFilter放行后逻辑.....");
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

在这里插入图片描述

过滤器的拦截路径配置

  Filter可以根据需求,配置不同的拦截资源路径:

拦截路径urlPatterns值含义
拦截具体路径/login只有访问 /login 路径时,才会被拦截
目录拦截/emps/*访问/emps下的所有资源,都会被拦截
拦截所有/*访问所有资源,都会被拦截
过滤器链

  过滤器链指的是在一个web应用程序当中,可以配置多个过滤器,多个过滤器就形成了一个过滤器链。
在这里插入图片描述
  如上图,定义了两个过滤器,这两个过滤器就形成了一个过滤器链。而这个链上的过滤器在执行的时候会一个一个的执行,会先执行第一个Filter,放行之后再来执行第二个Filter。要执行到最后一个过滤器放行之后,才会访问对应的web资源。如上图,先要执行过滤器2放行之后的逻辑,再来执行过滤器1放行之后的逻辑,最后再给浏览器响应数据。

Filter-登录校验

需求分析

要完成登录校验,主要是利用Filter过滤器实现,而Filter过滤器的流程步骤:
在这里插入图片描述

接口文档
请求路径:/login
请求方式:POST
接口描述:该接口用于员工登录Tlias智能学习辅助系统,登录完毕后,系统下发JWT令牌。

请求参数参数格式:application/json
请求数据样例:
	{
	"username": "jinyong",
	"password": "123456"
	}

响应数据参数格式:application/json
响应数据样例:
	{
	"code": 1,
	"msg": "success",
	"data":"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo"
	}

请求参数参数说明:
在这里插入图片描述

响应数据参数说明:
在这里插入图片描述

思路分析
基于上面业务流程,可以分析出具体的操作步骤:
	1. 获取请求url
	2. 判断请求url中是否包含login,如果包含,说明是登录操作,放行
	3. 获取请求头中的令牌(token)
	4. 判断令牌是否存在,如果不存在,返回错误结果(未登录)
	5. 解析token,如果解析失败,返回错误结果(未登录)
	6. 放行
功能开发

登录校验过滤器:LoginCheckFilter

@Slf4j
@WebFilter(urlPatterns = "/*") //拦截所有请求
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest,
                         ServletResponse servletResponse, FilterChain chain) throws
            IOException, ServletException {
        //前置:强制转换为http协议的请求对象、响应对象 (转换原因:要使用子类中特有方法)
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;

        //1.获取请求url
        String url = request.getRequestURL().toString();
        log.info("请求路径:{}", url); //请求路径:
        http://localhost:8080/login

        //2.判断请求url中是否包含login,如果包含,说明是登录操作,放行
        if(url.contains("/login")){
            chain.doFilter(request, response);//放行请求
            return;//结束当前方法的执行
        }

        //3.获取请求头中的令牌(token)
        String token = request.getHeader("token");
        log.info("从请求头中获取的令牌:{}",token);

        //4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
        if(!StringUtils.hasLength(token)){
            log.info("Token不存在");
            Result responseResult = Result.error("NOT_LOGIN");

            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            String json = JSONObject.toJSONString(responseResult);
            response.setContentType("application/json;charset=utf-8");

            //响应
            response.getWriter().write(json);
            return;
        }

        //5.解析token,如果解析失败,返回错误结果(未登录)
        try {
            JwtUtils.parseJWT(token);
        }catch (Exception e){
            log.info("令牌解析失败!");
            Result responseResult = Result.error("NOT_LOGIN");

            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            String json = JSONObject.toJSONString(responseResult);
            response.setContentType("application/json;charset=utf-8");

            //响应
            response.getWriter().write(json);
            return;
        }

        //6.放行
        chain.doFilter(request, response);
    }
}

在上述过滤器的功能实现中使用到了一个第三方json处理的工具包fastjson。我们要想使用,需要引入如下依赖:

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.76</version>
</dependency>

拦截器Interceptor

  拦截器是一种动态拦截方法调用的机制,类似于过滤器。拦截器是Spring框架中提供的,用来动态拦截控制器方法的执行。
  拦截器的作用:拦截请求,在指定方法调用前后,根据业务需要执行预先设定的代码。

Interceptor快速入门

拦截器的使用步骤和过滤器类似,也分为两步:
	1. 定义拦截器
	2. 注册配置拦截器

自定义拦截器: 实现HandlerInterceptor接口,并重写其所有方法

//自定义拦截器
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
	//目标资源方法执行前执行。 返回true:放行 ;返回false:不放行
	@Override
	public boolean preHandle(HttpServletRequest request,
		HttpServletResponse response, Object handler) throws Exception {
		System.out.println("preHandle .... ");
		return true; //true表示放行
	}
	
	//目标资源方法执行后执行
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		System.out.println("postHandle ... ");
	}
	
	//视图渲染完毕后执行,最后执行
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
		System.out.println("afterCompletion .... ");
	}
}

注册配置拦截器: 实现WebMvcConfigurer接口,并重写addInterceptors方法

@Configuration
public class WebConfig implements WebMvcConfigurer {
	//自定义的拦截器对象
	@Autowired
	private LoginCheckInterceptor loginCheckInterceptor;
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		//注册自定义拦截器对象
		registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**		");//设置拦截器拦截的请求路径( /** 表示拦截所有请求)
	}
}

Interceptor详解

拦截路径

  通过 addPathPatterns(“要拦截路径”) 方法,可以指定要拦截的资源,还可以调用 excludePathPatterns(“不拦截路径”) 方法,指定不拦截的资源。

@Configuration
public class WebConfig implements WebMvcConfigurer {
	//拦截器对象
	@Autowired
	private LoginCheckInterceptor loginCheckInterceptor;
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		//注册自定义拦截器对象
		registry.addInterceptor(loginCheckInterceptor)
		.addPathPatterns("/**")//设置拦截器拦截的请求路径( /**表示拦截所有请求)
		.excludePathPatterns("/login");//设置不拦截的请求路径
	}
}

  常见拦截路径设置:

在这里插入图片描述

执行流程

在这里插入图片描述

  当浏览器发起访问web应用时,此时定义的过滤器会拦截到请求。拦截到这次请求之后,先执行放行前的逻辑,然后再执行放行操作。而由于当前是基于springboot开发的,所以放行之后是进入到了spring的环境当中,也就是要来访问定义的controller当中的接口方法。
  Tomcat并不识别所编写的Controller程序,但是它识别Servlet程序,所以在Spring的Web环境中提供了一个非常核心的Servlet:DispatcherServlet(前端控制器),所有请求都会先进行到DispatcherServlet,再将请求转给Controller。
  当我们定义了拦截器后,会在执行Controller的方法之前,请求被拦截器拦截住。执行preHandle() 方法,这个方法执行完成后需要返回一个布尔类型的值,如果返回true,就表示放行本次操作,才会继续访问controller中的方法;如果返回false,则不会放行(controller中的方法也不会执行)。
  在controller当中的方法执行完毕之后,再回过来执行 postHandle() 这个方法以及afterCompletion() 方法,然后再返回给DispatcherServlet,最终再来执行过滤器当中放行后的这一部分逻辑的逻辑。执行完毕之后,最终给浏览器响应数据。

过滤器和拦截器的区别
过滤器和拦截器之间的区别主要是两点:
	接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。
	拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。

Interceptor-登录校验

  和登录校验Filter过滤器当中的逻辑是完全一致的,只需要把原来的过滤器换成拦截器interceptor就可以了。

登录校验拦截器

@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
    //前置方式
	@Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle .... ");

        //1.获取请求url
        String url = request.getRequestURL().toString();
        log.info("请求的ur1:{}",url);

        //2.判断请求url中是否包含login,如果包含,说明是登录操作,放行
        if (url.contains("login")){
            log.info("登录操作,放行……");
            return true;
        }

        //3.获取请求头中的令牌(token)
        String token = request.getHeader("token");
        log.info("从请求头中获取的令牌:{}",token);

        //4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
        if(!StringUtils.hasLength(token)){
            log.info("Token不存在");

            //创建响应结果对象
            Result responseResult = Result.error("NOT_LOGIN");
            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            String json = JSONObject.toJSONString(responseResult);

            //设置响应头(告知浏览器:响应的数据类型为json、响应的数据编码表为utf-8)
            response.setContentType("application/json;charset=utf-8");

            //响应
            response.getWriter().write(json);

            return false;//不放行
        }

        //5.解析token,如果解析失败,返回错误结果(未登录)
        try {
            JwtUtils.parseJWT(token);
        }catch (Exception e){
            log.info("令牌解析失败!");

            //创建响应结果对象
            Result responseResult = Result.error("NOT_LOGIN");

            //把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
            String json = JSONObject.toJSONString(responseResult);

            //设置响应头
            response.setContentType("application/json;charset=utf-8");

            //响应
            response.getWriter().write(json);
            return false;
        }

        //6.放行
        return true;
    }
}

注册配置拦截器


@Configuration
public class WebConfig implements WebMvcConfigurer {

    //自定义的拦截器对象
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册自定义拦截器对象
        registry.addInterceptor(loginCheckInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/login");
    }
}

异常处理

  出现异常之后,最终服务端给前端响应回来的数据是一个JSON格式的数据,但这种JSON格式的数据不是开发规范中所提到的统一响应结果Result,由于返回的数据不符合开发规范,所以前端并不能解析出响应的JSON数据。

在三层构架项目中,出现了异常,该如何处理?
	方案一:在所有Controller的所有方法中进行try…catch处理
	缺点:代码臃肿(不推荐)
	
	方案二:全局异常处理器
	好处:简单、优雅(推荐)

在这里插入图片描述

全局异常处理器

  我们该怎么样定义全局异常处理器?定义全局异常处理器非常简单,就是定义一个类,在类上加上一个注解@RestControllerAdvice,加上这个注解就代表我们定义了一个全局异常处理器。在全局异常处理器当中,需要定义一个方法来捕获异常,在这个方法上需要加上注解@ExceptionHandler。通过@ExceptionHandler注解当中的value属性来指定我们要捕获的是哪一类型的异常。


/*全局异常处理*/
@RestControllerAdvice
public class GlobalExceptionHandler {
    //处理异常
    @ExceptionHandler(Exception.class) //捕获所有异常
    public Result ex(Exception e){
        e.printStackTrace();//打印堆栈中的异常信息

        //捕获到异常之后,响应一个标准的Result
        return Result.error("对不起,操作失败,请联系管理员");
    }
}

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

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

相关文章

火星符号运算 - 华为OD统一考试

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 已知火星人使用的运算符号为 #和$ 其与地球人的等价公式如下 x#y2*x3*y4 x$y3*xy2x y是无符号整数。地球人公式按照c语言规则进行计算。火星人公式中&#xff0…

Qt PCL学习(三):点云滤波

注意事项 版本一览&#xff1a;Qt 5.15.2 PCL 1.12.1 VTK 9.1.0前置内容&#xff1a;Qt PCL学习&#xff08;一&#xff09;&#xff1a;环境搭建、Qt PCL学习&#xff08;二&#xff09;&#xff1a;点云读取与保存 0. 效果演示 1. pcl_open_save.pro QT core guigr…

【RT-DETR改进涨点】更加聚焦的边界框损失Focaler-IoU、InnerFocalerIoU(二次创新)

一、本文介绍 本文给大家带来的改进机制是更加聚焦的边界框损失Focaler-IoU已经我进行二次创新的InnerFocalerIoU同时本文的内容支持现阶段的百分之九十以上的IoU,比如Focaler-IoU、Focaler-ShapeIoU、Inner-Focaler-ShapeIoU包含非常全的损失函数,边界框的损失函数只看这一…

MySQL-视图/储存过程/触发器

一、视图 1.介绍 视图&#xff08;View&#xff09;是一种虚拟存在的表。视图中的数据并在数据库中实际存在&#xff0c;行和列数据来自定义视图的查询中使用的表&#xff0c;并且是在使用视图时动态生成的。 通俗的讲&#xff0c;视图只保存了查询的SQL逻辑&#xff0c;不保…

幻兽帕鲁服务器搭建,阿里云和腾讯云随便选,看看哪个简单?

幻兽帕鲁官方服务器不稳定&#xff1f;自己搭建幻兽帕鲁服务器&#xff0c;低延迟、稳定不卡&#xff0c;目前阿里云和腾讯云均推出幻兽帕鲁专用服务器&#xff0c;腾讯云直接提供幻兽帕鲁镜像系统&#xff0c;阿里云通过计算巢服务&#xff0c;均可以一键部署&#xff0c;鼠标…

Redis核心技术与实战【学习笔记】 - 23.Redis 主从切换故障,有哪些坑

前言 Redis 的主从同步机制不仅可以让从库服务更多的读请求&#xff0c;分担主库的压力&#xff0c;而且还能在主库发生故障时&#xff0c;进行主从库切换&#xff0c;提供高可靠服务。 不过&#xff0c;在实际使用主从机制时会踩到一些“坑”&#xff1a;主从数据不一致、读…

数据结构第十四天(树的存储/双亲表示法)

目录 前言 概述 接口&#xff1a; 源码&#xff1a; 测试函数&#xff1a; 运行结果&#xff1a; 往期精彩内容 前言 孩子&#xff0c;一定要记得你的父母啊&#xff01;&#xff01;&#xff01; 哈哈&#xff0c;今天开始学习树结构中的双亲表示法&#xff0c;让孩…

YOLOv5独家原创改进:大核卷积涨点系列| Shift-ConvNets,稀疏/移位操作让小卷积核也能达到大卷积核效果 | 2024年最新论文

💡💡💡本文独家改进:大的卷积核设计成为使卷积神经网络(CNNs)再次强大的理想解决方案,Shift-ConvNets稀疏/移位操作让小卷积核也能达到大卷积核效果,创新十足实现涨点,助力YOLOv8 💡💡💡在多个私有数据集和公开数据集VisDrone2019、PASCAL VOC实现涨点 收录…

VSCode如何让先前打开的文件不被自动关闭,一直保持在标签栏里(关闭预览模式)

第一次接触VSCode-Huawei IDE编辑器&#xff0c;每次打开一个新的代码文件&#xff0c;旧的代码文件都会被自动关闭&#xff08;现在才知道是因为文件默认是以预览模式打开展示的&#xff09;。 那么如何才能让先前打开的文件一直保持在标签栏里呢&#xff1f; 我们需要去设置…

Mac电脑如何通过终端隐藏应用程序?

在我们使用Mac电脑的时候难免会遇到想要不想看到某个应用程序又不想卸载它们。值得庆幸的是&#xff0c;macOS具有一些强大的文件管理功能&#xff0c;允许用户轻松隐藏&#xff08;以及稍后显示&#xff09;文件甚至应用程序。 那么&#xff0c;Mac电脑如何通过终端隐藏应用程…

Composition Local

1.显示传参 package com.jmj.jetpackcomposecompositionlocalimport org.junit.Testimport org.junit.Assert.*/*** 显示传参*/ class ExplicitText {private fun Layout(){var color:String "黑色";//参数需要通过层层传递&#xff0c;比较繁琐Text(color)Grid(c…

idea: 无法创建Java Class文件(SpringBoot)已解决

第一&#xff1a;点击file-->project Sructure... 第二步&#xff1a;点击Moudules 选择自己需要创建java的文件夹&#xff08;我这里选择的是main&#xff09;右键点击Sources&#xff0c;然后点击OK即可 然后就可以创建java类了

EasyRecovery免费版2024电脑数据恢复利器

在数字化时代&#xff0c;我们的生活和工作都离不开电脑&#xff0c;电脑硬盘中的数据却时常面临丢失的风险&#xff0c;无论是因为误删除、格式化、病毒感染还是硬件故障&#xff0c;都可能让我们付出沉重的代价&#xff0c;在这种情况下&#xff0c;一款强大的数据恢复软件就…

深度学习在知识图谱问答中的革新与挑战

目录 前言1 背景知识2 基于深度学习改进问句解析模型2.1 谓词匹配2.2 问句解析2.3 逐步生成查询图 3 基于深度学习的端到端模型3.1 端到端框架3.2 简单嵌入技术 4 优势4.1 深入的问题表示4.2 实体关系表示深挖4.3 候选答案排序效果好 5 挑战5.1 依赖大量训练语料5.2 推理类问句…

Python常见的免杀方式

10.1节介绍了通过msfvenom生成shellcode &#xff0c;并通过Python程序加载执行&#xff0c;又 介绍了如何将Python的.py文件生成为exe文件。使用pyinstaller生成的可执行文件 本身就具有一定的免杀能力&#xff0c;但是在与杀毒软件对抗时&#xff0c;部分杀毒软件也可以通 过…

双非本科准备秋招(21.2)—— ReentrantLock

一、vs synchronized 可中断可以设置超时时间可以设置为公平锁支持多个条件变量 语法&#xff1a; // 获取锁reentrantLock.lock();try {// 临界区} finally {// 释放锁reentrantLock.unlock();} 二、可重入 连续三次上锁。 Slf4j(topic "c.test") public class…

软件应用实例分享,电玩计时计费怎么算,佳易王PS5游戏计时器系统程序教程

软件应用实例分享&#xff0c;电玩计时计费怎么算&#xff0c;佳易王PS5游戏计时器系统程序教程 一、前言 以下软件教程以 佳易王电玩计时计费管理系统软件V17.9为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 点击开始计时后&#xff0c;图片…

【深度学习:SegGPT】在上下文中分割所有内容 [解释]

【深度学习&#xff1a;SegGPT】在上下文中分割所有内容 [解释] SegGPT与以前的模型相比如何&#xff1f;SegGPT在实践中是如何工作的&#xff1f;SegGPT培训计划上下文着色上下文集成上下文调整SegGPT 训练参数 如何尝试 SegGPT&#xff1f;使用哪些数据集来训练 SegGPT&#…

前端页面禁止debugger调试并跳转空白页面----文心一言官网实现方式

技术点&#xff1a;setInterval定时器Object.defineProperty 背景&#xff1a; 某天打开文心一言想看看接口返回结构是怎样的&#xff0c;熟练的打开浏览器开发者工具查看网络请求。 发现出现了以下debugger断点 这难不倒我&#xff0c;去掉断点调试&#xff0c;继续下一步不…

Django模板(三)

一、标签URL 返回与给定视图和可选参数相匹配的绝对路径引用(不含域名的 URL) {% url some-url-name v1 v2 %} 第一个参数是url模式名称,后面跟着的是参数,以空格分隔可以使用关键字: {% url some-url-name arg1=v1 arg2=v2 %}如果您想检索命名空间的URL,请指定完全限定…