spring security 前后端分离 进行用户验证 权限登陆的实现代码(看不懂??直接cv)

news2025/1/19 14:37:21

目录

前言:

一.所需依赖

二.application.properties

 三.工具类

3.1ApplicationContextUtils

3.2JwtUtils

 3.3ResponseResult

3.4ResponseStatus 

3.5RsaUtils

四.UserDetailServiceImpl

 

五.成功处理器

 六.SecurityConfig

七. filter


前言:

前后端分离项目运行流程

我之前的博客写了一篇前后端不分离的权限验证,前后端分离就是在原来的基础上加上发送token给前端,前端发送请求给服务器需要携带token。不太懂的朋友请先移步(29条消息) springsecurity基于数据库中的用户信息实现登陆_代码大帝的博客-CSDN博客

嫌麻烦的同学也可以直接把配置代码拿来用,代码都有写的。

一.所需依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.dmdd</groupId>
    <artifactId>javatestspringsecurity</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>javatestspringsecurity</name>
    <description>javatestspringsecurity</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.9.9</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-annotation</artifactId>
            <version>3.5.2</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

直接拿来用。

二.application.properties

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/edu_user?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=jly720609
mybatis-plus.type-aliases-package=com.dmdd.javatestspringsecurity.entity
mybatis-plus.mapper-locations=classpath:mapper/*.xml


懂的都懂

 三.工具类

包含生成公钥秘钥,对象转json等一系列方法

3.1ApplicationContextUtils

package com.dmdd.javatestspringsecurity.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 应用程序上下文工具
 * 程序启动后,会创建ApplicationContext对象
 * ApplicationContextAware能感知到ApplicationContext对象
 * 自动调用setApplicationContext方法
 */
@Component
public class ApplicationContextUtils implements ApplicationContextAware {

    //系统的IOC容器
    private static ApplicationContext applicationContext = null;

    //感知到上下文后,自动调用,获得上下文
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextUtils.applicationContext = applicationContext;
    }

    //返回对象
    public static <T> T getBean(Class<T> tClass){
        return applicationContext.getBean(tClass);
    }
}

3.2JwtUtils

package com.dmdd.javatestspringsecurity.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;

import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * JWT工具类
 */
public class JwtUtils {

    public static final String JWT_KEY_USERNAME = "username";
    public static final int EXPIRE_MINUTES = 120;

    /**
     * 私钥加密token
     */
    public static String generateToken(String username, PrivateKey privateKey, int expireMinutes) {

        return Jwts.builder()
                .claim(JWT_KEY_USERNAME, username)
                .setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate())
                .signWith(SignatureAlgorithm.RS256, privateKey)
                .compact();
    }

    /**
     * 从token解析用户
     *
     * @param token
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static String getUsernameFromToken(String token, PublicKey publicKey){
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
        Claims body = claimsJws.getBody();
        String username = (String) body.get(JWT_KEY_USERNAME);
        return username;
    }
}

 3.3ResponseResult

package com.dmdd.javatestspringsecurity.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;

import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * JWT工具类
 */
public class JwtUtils {

    public static final String JWT_KEY_USERNAME = "username";
    public static final int EXPIRE_MINUTES = 120;

    /**
     * 私钥加密token
     */
    public static String generateToken(String username, PrivateKey privateKey, int expireMinutes) {

        return Jwts.builder()
                .claim(JWT_KEY_USERNAME, username)
                .setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate())
                .signWith(SignatureAlgorithm.RS256, privateKey)
                .compact();
    }

    /**
     * 从token解析用户
     *
     * @param token
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static String getUsernameFromToken(String token, PublicKey publicKey){
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
        Claims body = claimsJws.getBody();
        String username = (String) body.get(JWT_KEY_USERNAME);
        return username;
    }
}

3.4ResponseStatus 

package com.dmdd.javatestspringsecurity.util;

/**
 * 响应状态枚举
 */
public enum ResponseStatus {
    /**
     * 内置状态
     */
    OK(200,"操作成功"),
    INTERNAL_ERROR(500000,"系统错误"),
    BUSINESS_ERROR(500001,"业务错误"),
    LOGIN_ERROR(500002,"账号或密码错误"),
    NO_DATA_ERROR(500003,"没有找到数据"),
    PARAM_ERROR(500004,"参数格式错误"),
    AUTH_ERROR(401,"没有权限,需要登录");

    //响应代码
    private Integer code;
    //响应消息
    private String message;

    public Integer getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    ResponseStatus(Integer status, String message) {
        this.code = status;
        this.message = message;
    }
}

3.5RsaUtils

package com.dmdd.javatestspringsecurity.util;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA工具类
 */
public class RsaUtils {

    public static final String RSA_SECRET = "blbweb@#$%"; //秘钥
    public static final String RSA_PATH = System.getProperty("user.dir")+"/rsa/";//秘钥保存位置
    public static final String RSA_PUB_KEY_PATH = RSA_PATH + "pubKey.rsa";//公钥路径
    public static final String RSA_PRI_KEY_PATH = RSA_PATH + "priKey.rsa";//私钥路径

    public static PublicKey publicKey; //公钥
    public static PrivateKey privateKey; //私钥

    /**
     * 类加载后,生成公钥和私钥文件
     */
    static {
        try {
            File rsa = new File(RSA_PATH);
            if (!rsa.exists()) {
                rsa.mkdirs();
            }
            File pubKey = new File(RSA_PUB_KEY_PATH);
            File priKey = new File(RSA_PRI_KEY_PATH);
            //判断公钥和私钥如果不存在就创建
            if (!priKey.exists() || !pubKey.exists()) {
                //创建公钥和私钥文件
                RsaUtils.generateKey(RSA_PUB_KEY_PATH, RSA_PRI_KEY_PATH, RSA_SECRET);
            }
            //读取公钥和私钥内容
            publicKey = RsaUtils.getPublicKey(RSA_PUB_KEY_PATH);
            privateKey = RsaUtils.getPrivateKey(RSA_PRI_KEY_PATH);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
    }

    /**
     * 从文件中读取公钥
     *
     * @param filename 公钥保存路径,相对于classpath
     * @return 公钥对象
     * @throws Exception
     */
    public static PublicKey getPublicKey(String filename) throws Exception {
        byte[] bytes = readFile(filename);
        return getPublicKey(bytes);
    }

    /**
     * 从文件中读取密钥
     *
     * @param filename 私钥保存路径,相对于classpath
     * @return 私钥对象
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String filename) throws Exception {
        byte[] bytes = readFile(filename);
        return getPrivateKey(bytes);
    }

    /**
     * 获取公钥
     *
     * @param bytes 公钥的字节形式
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(byte[] bytes) throws Exception {
        X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        return factory.generatePublic(spec);
    }

    /**
     * 获取密钥
     *
     * @param bytes 私钥的字节形式
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(byte[] bytes) throws Exception {
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        return factory.generatePrivate(spec);
    }

    /**
     * 根据密文,生存rsa公钥和私钥,并写入指定文件
     *
     * @param publicKeyFilename  公钥文件路径
     * @param privateKeyFilename 私钥文件路径
     * @param secret             生成密钥的密文
     * @throws IOException
     * @throws NoSuchAlgorithmException
     */
    public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret) throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        SecureRandom secureRandom = new SecureRandom(secret.getBytes());
        keyPairGenerator.initialize(1024, secureRandom);
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        // 获取公钥并写出
        byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
        writeFile(publicKeyFilename, publicKeyBytes);
        // 获取私钥并写出
        byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
        writeFile(privateKeyFilename, privateKeyBytes);
    }

    private static byte[] readFile(String fileName) throws Exception {
        return Files.readAllBytes(new File(fileName).toPath());
    }

    private static void writeFile(String destPath, byte[] bytes) throws IOException {
        File dest = new File(destPath);
        if (!dest.exists()) {
            dest.createNewFile();
        }
        Files.write(dest.toPath(), bytes);
    }
}

四.UserDetailServiceImpl

package com.dmdd.javatestspringsecurity.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dmdd.javatestspringsecurity.entity.User;
import com.dmdd.javatestspringsecurity.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 实现自定义用户登录逻辑
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private IUserService userService;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //按用户名查询用户信息
        User user = userService.getOne(new QueryWrapper<User>().lambda().eq(User::getUsername, s));
        if (user == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        //查询所有用户权限 List<String> --> xx,xxx,xxx,xx --> List<Authory>
        List<String> authList = userService.getAuthoritiesByUsername(s);
        String auths = String.join(",", authList);
        //把用户信息包装到UserDetails的实现类User中
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
                AuthorityUtils.commaSeparatedStringToAuthorityList(auths));
    }
}

1.这个类需要实现UserDetailService接口

2.重写loadUserBYUsername方法

3.将用户名,密码,授权信息包装到UserDetails的实现类User中。

五.成功处理器

package com.dmdd.javatestspringsecurity.config;

import com.dmdd.javatestspringsecurity.entity.vo.UserTokenVO;
import com.dmdd.javatestspringsecurity.util.JwtUtils;
import com.dmdd.javatestspringsecurity.util.ResponseResult;
import com.dmdd.javatestspringsecurity.util.RsaUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 登录成功处理器
 */
@Slf4j
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {

    //登录成功的回调
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        //获得用户名
        User user = (User) authentication.getPrincipal();
        //生成token字符串
        String token = JwtUtils.generateToken(user.getUsername(), RsaUtils.privateKey, JwtUtils.EXPIRE_MINUTES);
        log.info("生成token:{}",token);
        //发送token给前端
        ResponseResult.write(httpServletResponse,ResponseResult.ok(new UserTokenVO(user.getUsername(),token)));
    }
}

 因为项目前后端分离,服务器内不再拥有前端代码。所以不能直接用url的形式进行登陆成功后的跳转。因此采用成功处理器将用户名,秘钥,以及存活时间包装成token响应给前端

 六.SecurityConfig

package com.dmdd.javatestspringsecurity.config;

import com.dmdd.javatestspringsecurity.filter.RequestAuthenticationFilter;
import com.dmdd.javatestspringsecurity.util.ResponseResult;
import com.dmdd.javatestspringsecurity.util.ResponseStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

/**
 * SpringSecurity的核心配置
 */
//启动权限控制的注解
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
//启动Security的验证
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //提供密码编码器
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private LoginSuccessHandler loginSuccessHandler;

    //配置验证用户的账号和密码
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //数据库用户验证
        auth.userDetailsService(userDetailsService);
    }

    //配置访问控制
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //给请求授权
        http.authorizeRequests()
                //给登录相关的请求放行
                .antMatchers("/login","/logout").permitAll()
                //访问控制
                //其余的都拦截
                .anyRequest().authenticated()
                .and()
                //配置自定义登录
                .formLogin()
                .successHandler(loginSuccessHandler)//成功处理器
                .failureHandler(((httpServletRequest, httpServletResponse, e) -> { //登录失败处理器
                    ResponseResult.write(httpServletResponse,ResponseResult.error(ResponseStatus.LOGIN_ERROR));
                }))
                .and()
                .logout() //配置注销
                .logoutSuccessHandler(((httpServletRequest, httpServletResponse, authentication) -> { //注销成功
                    ResponseResult.write(httpServletResponse,ResponseResult.ok(ResponseStatus.OK));
                }))
                .clearAuthentication(true) //清除验证信息
                .and()
                .cors() //配置跨域
                .configurationSource(corsConfigurationSource())
                .and()
                .csrf().disable() //停止csrf
                .sessionManagement() //session管理
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS) //无状态,不使用session
                .and()
                .addFilter(new RequestAuthenticationFilter(authenticationManager())) //添加自定义验证过滤器
        ;
    }

    /**
     * 跨域配置对象
     * @return
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        //配置允许访问的服务器域名
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

 可以直接拿来用。

七. filter

package com.dmdd.javatestspringsecurity.filter;

import com.dmdd.javatestspringsecurity.service.IUserService;
import com.dmdd.javatestspringsecurity.util.ApplicationContextUtils;
import com.dmdd.javatestspringsecurity.util.JwtUtils;
import com.dmdd.javatestspringsecurity.util.RsaUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * 请求验证过滤器
 */
@Slf4j
public class RequestAuthenticationFilter extends BasicAuthenticationFilter {

    public static final String AUTH_HEADER = "Authorization";

    //通过工具类获得service对象
    private IUserService userService = ApplicationContextUtils.getBean(IUserService.class);

    public RequestAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    //请求的过滤
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //从请求头获得token
        String token = request.getHeader(AUTH_HEADER);
        if(StringUtils.isEmpty(token)){
            //从请求参数获得token
            token = request.getParameter(AUTH_HEADER);
        }
        //如果读取不到,就拦截
        if(StringUtils.isEmpty(token)){
            log.info("读取不到token,请求{}被拦截",request.getRequestURL());
            chain.doFilter(request,response);
            return;
        }
        try {
            //对token进行解析
            String username = JwtUtils.getUsernameFromToken(token, RsaUtils.publicKey);
            //将用户的权限查询出来
            List<String> authList = userService.getAuthoritiesByUsername(username);
            List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",", authList));
            //创建通行证
            UsernamePasswordAuthenticationToken authToken = new
                    UsernamePasswordAuthenticationToken(username,"",authorities);
            //把通行证交给Security
            SecurityContextHolder.getContext().setAuthentication(authToken);
        }catch (Exception ex){
            log.error("解析token失败",ex);
        }
        chain.doFilter(request,response);
    }
}

主要作用就是解析前端发过来的token,验证是否通过登陆,防止异常数据攻击服务器

注意:查询用户权限的方法需要自己编写

通过用户名查询该用户有哪些权限。然后交给服务器设置哪些接口需要哪些权限可以使用

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

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

相关文章

多个路由器的局域网终端设备的资源访问

多个路由器之间资源的访问 本质是将路由设备放置到一个网段 中继路由 中继的路由可以看作是另一个路由中的一个终端设备&#xff0c;只是为了延长传递wifi&#xff0c;在使用ipcofig中的网关和主路由的网关一样&#xff0c;一般都是主路由的IP。 无线桥接的中继路由 无论是…

车-电-路网时空分布负荷预测研究(Matlab代码)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

使用c语言连接mysql数据库并且批量插入数据

​ 使用从c连接数据库需要在本机安装数据库&#xff0c;或者拿到数据库所在主机的IP地址。先说明我使用的是mysql8.0 64位的数据库&#xff0c;使用的vs是vs2019。 1.配置环境 首先打开vs2019&#xff0c;创建一个空项目&#xff0c;让后右击下图所示位置&#xff0c;然…

网络编程套接字之UDP

文章目录一、网络编程二、UDP数据报套接字编程DatagramSocketDatagramPacket实现客户端服务器程序EchoServer客户端一、网络编程 我们网络编程的核心: Socket API&#xff0c;操作系统为我们应用程序提供的API&#xff0c;我们的Socket是和传输层密切相关的。 我们传输层为我…

SpringBoot+Vue+Wx健康上报系统

简介&#xff1a;本项目采用了基本的springbootvueWx设计健康上报系统。详情请看截图。经测试&#xff0c;本项目正常运行。本项目适用于Java毕业设计、课程设计学习参考等用途。 项目描述 项目名称SpringBootVueWx健康上报系统源码作者LHL项目类型Java EE项目 &#xff08;前…

多线程初阶——线程状态

多线程初阶——线程状态 文章目录多线程初阶——线程状态1.Thread类及常见构造方法2.Thread常见的方法3.线程相关的重要操作3.1启动线程—start()3.2中断线程3.3 等待线程— join()3.4 获取线程引用3.5休眠线程—sleep()4.线程的状态1.Thread类及常见构造方法 方法说明Thread(…

前端js实现根据文件url批量压缩下载成zip包

前言 项目开发中&#xff0c;产品经理提了这样一个需求&#xff1a;将系统中的附件实现批量打包下载功能。本来系统中是有单个下载及批量下载功能&#xff0c;现在应业务方的需求&#xff0c;需要多加个批量打包下载。 初步设想是&#xff1a;由后端编写接口实现。但后来经过思…

从事测试开发8年,聊聊我是怎么从0基础到年薪40万的

本人从事测试开发8年多&#xff0c;之前在猪场工作&#xff0c;年薪突破40W&#xff0c;算是一个生活过得去的码农。&#xff08;仅代表本人&#xff09;目前从事软件测试行业的薪资待遇还是很不错的&#xff0c;所以如果朋友们真的对软件测试感兴趣的话可以坚持学下去&#xf…

Java native agent学习笔记-从加载到log4j漏洞检测

记录一下java native agent的学习过程,也顺便造一个检测log4j漏洞的轮子: java native agent相比java agent最大的好处是快,C写的,快的一笔,但是最大的坏处是非常麻烦,毕竟你拿个面过程的语言怼面对象的肯定是比较麻烦的。 本次学习的目的是做个加载器,动态加载agent,然后再实…

研究人员发布 VMware vRealize Log RCE 漏洞,立即打补丁

Horizon3 攻击团队的安全研究人员将于下周发布一个针对漏洞链的漏洞利用程序&#xff0c;以在未打补丁的 VMware vRealize Log Insight 设备上获得远程代码执行。 vRealize Log Insight 现在称为 VMware Aria Operations for Logs&#xff0c;它使 VMware 管理员可以更轻松地分…

每日学术速递2.4

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.LG、cs.AI 1.Neuro Symbolic Continual Learning: Knowledge, Reasoning Shortcuts and Concept Rehearsal 标题&#xff1a;神经象征性的持续学习&#xff1a;知识、推理捷径和概念排练…

必须掌握的网络安全知识

没有网络安全&#xff0c;就没有国家安全。网络安全和保密防护&#xff0c;是机关单位日常工作中不可忽视的重要问题。尤其在涉密单位工作的人员&#xff0c;因工作性质特殊&#xff0c;不仅要了解非涉密网络的安全操作常识&#xff0c;更要重点了解涉密网络的规范行为要点&…

2021年上半年信息系统项目管理师真题与答案完整版(综合知识、案例分析、论文)

1、 国家信息化体系包括六个要素&#xff0c;其中&#xff08;&#xff09;是信息化体系六要素中的龙头&#xff0c;是国家信息化建设的主阵地&#xff0c;集中体现了国家信息化建设的需求和效益。A、信息资源 B、信息技术应用 C、信息网络 D、信息化政策法规和标准规范0参考答…

若依代码生成器------数据库篇

继上一篇《若依代码自动生成器研究-表查询篇》&#xff0c;我们继续来学习若依系统中的代码生成逻辑。 导入表之Sql查询 在菜单栏点击“代码生成”&#xff0c;在右侧栏中点击“导入”按钮&#xff0c;在文章若依中的代码自动生成器研究-表查询篇中&#xff0c;我们已经一直…

三十六、Kubernetes1.25中数据存储第一篇

1、概述在前面已经提到&#xff0c;容器的生命周期可能很短&#xff0c;会被频繁地创建和销毁。那么容器在销毁时&#xff0c;保存在容器中的数据也会被清除。这种结果对用户来说&#xff0c;在某些情况下是不乐意看到的。为了持久化保存容器的数据&#xff0c;kubernetes引入了…

【深度学习】对SSD与Retina的理解

SSD 正负样本选择 同YOLO 选择与GT IOU最大的anchor作为正样本。(此时正负样本很不平衡)对于剩余未匹配anchor,将与GT IOU超过0.5的作为正样本。这样一个GT就可以匹配多个anchor,增加正样本的数量。(此时负样本依然多于正样本)hard negative mining,难负样本挖掘。将所有…

重定向的概述和使用(基于web方面),很简单

大家好&#xff0c;今天分享一下重定向的概述以及使用 我们要知道&#xff0c;重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置 同时&#xff0c;重定向有好几类 1.网页重定向、 2.域名的重定向、 3.路由选择 4. Linux上的文件重定向操作 就是要知…

QTransform的使用

目录引言基础知识缩放矩阵平移矩阵旋转矩阵矩阵乘法实际使用实现思路完整代码参考资料引言 A transformation specifies how to translate, scale, shear, rotate or project the coordinate system, and is typically used when rendering graphics. A QTransform object can …

6 -【Faster R-CNN 代码精读】之 Proposals 、 Filter Proposals

6 -【Faster R-CNN 代码精读】之 Proposals 、 Filter Proposals1、前言2、数据回顾3、计算候选框位置&#xff08;proposal coordinates&#xff09;4、筛选候选框&#xff08;filter proposals&#xff09;及相关处理1&#xff09;筛选出 预测概率 排前 2000 的proposals2&am…

TCP协议面试灵魂12 问(四)

005: 介绍一下 TCP 报文头部的字段 报文头部结构如下(单位为字节): 请大家牢记这张图&#xff01; 源端口、目标端口 如何标识唯一标识一个连接&#xff1f;答案是 TCP 连接的四元组——源 IP、源端口、目标 IP 和目标端口。 那 TCP 报文怎么没有源 IP 和目标 IP 呢&#x…