欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot3+SpringSecurity6前后端分離的項(xiàng)目實(shí)踐

 更新時(shí)間:2023年12月29日 10:11:29   作者:翰戈.summer  
SpringSecurity6 的用法和以前版本的有較大差別,本文主要介紹了SpringBoot3+SpringSecurity6前后端分離的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下

網(wǎng)上能找到的SpringBoot項(xiàng)目一般都是SpringBoot2 + SpringSecurity5,甚至是SSM的項(xiàng)目。這些老版本的教程很多已經(jīng)不適用了,對(duì)于現(xiàn)在大部分的初學(xué)者來說,學(xué)了可能也是經(jīng)典白雪。我還是不愿學(xué)那些老版本的東西,所以自己摸索了一下新版的SpringBoot項(xiàng)目應(yīng)該怎么寫。學(xué)習(xí)的過程也是非常折磨人的,看了很多的教程才知道個(gè)大概。

導(dǎo)入依賴

SpringSecurity依賴

<!--SpringSecurity起步依賴-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

JWT依賴

<!--jwt令牌-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

添加配置類

對(duì)Security進(jìn)行配置,Security中很多的默認(rèn)配置都可以用自定義的替換。

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

/**
 * @Description: SpringSecurity配置類
 * @Author: 翰戈.summer
 * @Date: 2023/11/17
 * @Param:
 * @Return:
 */
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final UserDetailsService userDetailsService;

    /**
     * 加載用戶信息
     */
    @Bean
    public UserDetailsService userDetailsService() {
        return userDetailsService;
    }

    /**
     * 密碼編碼器
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 身份驗(yàn)證管理器
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    /**
     * 處理身份驗(yàn)證
     */
    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        return daoAuthenticationProvider;
    }

    /**
     * @Description: 配置SecurityFilterChain過濾器鏈
     * @Author: 翰戈.summer
     * @Date: 2023/11/17
     * @Param: HttpSecurity
     * @Return: SecurityFilterChain
     */
    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
                .requestMatchers(HttpMethod.POST, "/api/user/login").permitAll() //登錄放行
                .anyRequest().authenticated()
        );
        httpSecurity.authenticationProvider(authenticationProvider());

        //禁用登錄頁面
        httpSecurity.formLogin(AbstractHttpConfigurer::disable);
        //禁用登出頁面
        httpSecurity.logout(AbstractHttpConfigurer::disable);
        //禁用session
        httpSecurity.sessionManagement(AbstractHttpConfigurer::disable);
        //禁用httpBasic
        httpSecurity.httpBasic(AbstractHttpConfigurer::disable);
        //禁用csrf保護(hù)
        httpSecurity.csrf(AbstractHttpConfigurer::disable);

        return httpSecurity.build();
    }
}

實(shí)現(xiàn)UserDetailsService

其中UserMapper、AuthorityMapper需要自己創(chuàng)建,不是重點(diǎn)。這兩個(gè)Mapper的作用是獲取用戶信息(用戶名、密碼、用戶權(quán)限),封裝到User中返回給Security。

import com.demo.mapper.AuthorityMapper;
import com.demo.mapper.UserMapper;
import com.demo.pojo.AuthorityEntity;
import com.demo.pojo.UserEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
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;
import java.util.StringJoiner;

/**
 * @Description: 用戶登錄
 * @Author: 翰戈.summer
 * @Date: 2023/11/16
 * @Param:
 * @Return:
 */
@Service
@RequiredArgsConstructor
public class UserLoginDetailsServiceImpl implements UserDetailsService {

    private final UserMapper userMapper;
    private final AuthorityMapper authorityMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserEntity userEntity = userMapper.selectUserByUsername(username);

        List<AuthorityEntity> authorities = authorityMapper.selectAuthorityByUsername(username);
        StringJoiner stringJoiner = new StringJoiner(",", "", "");

        authorities.forEach(authority -> stringJoiner.add(authority.getAuthorityName()));

        return new User(userEntity.getUsername(), userEntity.getPassword(),
                AuthorityUtils.commaSeparatedStringToAuthorityList(stringJoiner.toString())
        );
    }
}

實(shí)現(xiàn)UserDetails

登錄操作會(huì)用到UserDetails,用于獲取用戶名和權(quán)限。

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

/**
 * @Description: SpringSecurity用戶實(shí)體類
 * @Author: 翰戈.summer
 * @Date: 2023/11/18
 * @Param:
 * @Return:
 */
@NoArgsConstructor
@AllArgsConstructor
public class UserDetailsEntity implements UserDetails {

    private String username;
    private String password;
    private Collection<? extends GrantedAuthority> authorities;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public String toString() {
        return "UserDetailsEntity{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", authorities=" + authorities +
                '}';
    }
}

JWT工具類 

生成 jwt令牌 或解析,其中的JwtProperties(jwt令牌配置屬性類)可以自己創(chuàng)建,不是重點(diǎn)。

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Map;

/**
 * @Description: 生成和解析jwt令牌
 * @Author: 翰戈.summer
 * @Date: 2023/11/16
 * @Param:
 * @Return:
 */
@Component
@RequiredArgsConstructor
public class JwtUtils {

    private final JwtProperties jwtProperties;

    /**
     * @Description: 生成令牌
     * @Author: 翰戈.summer
     * @Date: 2023/11/16
     * @Param: Map
     * @Return: String jwt
     */
    public String getJwt(Map<String, Object> claims) {

        String signingKey = jwtProperties.getSigningKey();
        Long expire = jwtProperties.getExpire();

        return Jwts.builder()
                .setClaims(claims) //設(shè)置載荷內(nèi)容
                .signWith(SignatureAlgorithm.HS256, signingKey) //設(shè)置簽名算法
                .setExpiration(new Date(System.currentTimeMillis() + expire)) //設(shè)置有效時(shí)間
                .compact();
    }

    /**
     * @Description: 解析令牌
     * @Author: 翰戈.summer
     * @Date: 2023/11/16
     * @Param: String jwt
     * @Return: Claims claims
     */
    public Claims parseJwt(String jwt) {

        String signingKey = jwtProperties.getSigningKey();

        return Jwts.parser()
                .setSigningKey(signingKey) //指定簽名密鑰
                .parseClaimsJws(jwt) //開始解析令牌
                .getBody();
    }
}

登錄接口

用戶登錄成功并返回 jwt令牌,Result為統(tǒng)一響應(yīng)的結(jié)果,UserLoginDTO用于封裝用戶登錄信息,其中的UserDetails必須實(shí)現(xiàn)后才能獲取到用戶信息。

import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 用戶登錄操作相關(guān)接口
 * @Author: 翰戈.summer
 * @Date: 2023/11/20
 * @Param:
 * @Return:
 */
@RestController
@RequestMapping("/api/user/login")
@RequiredArgsConstructor
public class UserLoginController {

    private final AuthenticationManager authenticationManager;

    private final JwtUtils jwtUtils;

    @PostMapping
    public Result<String> doLogin(@RequestBody UserLoginDTO userLoginDTO) {
        try {
            UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userLoginDTO.getUsername(), userLoginDTO.getPassword());
            Authentication authentication = authenticationManager.authenticate(auth);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();

            //獲取用戶權(quán)限信息
            String authorityString = "";
            Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                authorityString = authority.getAuthority();
            }

            //用戶身份驗(yàn)證成功,生成并返回jwt令牌
            Map<String, Object> claims = new HashMap<>();
            claims.put("username", userDetails.getUsername());
            claims.put("authorityString", authorityString);
            String jwtToken = jwtUtils.getJwt(claims);
            return Result.success(jwtToken);
        } catch (Exception ex) {
            //用戶身份驗(yàn)證失敗,返回登陸失敗提示
            return Result.error("用戶名或密碼錯(cuò)誤!");
        }
    }
}

自定義token過濾器

過濾器中拋出的異常是不會(huì)被全局異常處理器捕獲到的,直接返回錯(cuò)誤結(jié)果。這里用到了SpringContextUtils通過上下文來獲取Bean組件,下面會(huì)提供。

過濾器屬于Servlet(作用范圍更大),攔截器屬于SpringMVC(作用范圍較?。之惓L幚砥髦荒懿东@到攔截器中的異常。在過濾器中無法初始化Bean組件,可以通過上下文來獲取。

import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Collections;

/**
 * @Description: 自定義token驗(yàn)證過濾器,驗(yàn)證成功后將用戶信息放入SecurityContext上下文
 * @Author: 翰戈.summer
 * @Date: 2023/11/18
 * @Param:
 * @Return:
 */
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

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

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException {
        try {
            //獲取請(qǐng)求頭中的token
            String jwtToken = request.getHeader("token");
            if (!StringUtils.hasLength(jwtToken)) {
                //token不存在,交給其他過濾器處理
                filterChain.doFilter(request, response);
                return; //結(jié)束方法
            }

            //過濾器中無法初始化Bean組件,使用上下文獲取
            JwtUtils jwtUtils = SpringContextUtils.getBean("jwtUtils");
            if (jwtUtils == null) {
                throw new RuntimeException();
            }

            //解析jwt令牌
            Claims claims;
            try {
                claims = jwtUtils.parseJwt(jwtToken);
            } catch (Exception ex) {
                throw new RuntimeException();
            }

            //獲取用戶信息
            String username = (String) claims.get("username"); //用戶名
            String authorityString = (String) claims.get("authorityString"); //權(quán)限信息

            Authentication authentication = new UsernamePasswordAuthenticationToken(
                    username, null,
                    Collections.singleton(new SimpleGrantedAuthority(authorityString))
            );

            //將用戶信息放入SecurityContext上下文
            SecurityContextHolder.getContext().setAuthentication(authentication);

            filterChain.doFilter(request, response);
        } catch (Exception ex) {
            //過濾器中拋出的異常無法被全局異常處理器捕獲,直接返回錯(cuò)誤結(jié)果
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json; charset=utf-8");
            String value = new ObjectMapper().writeValueAsString(Result.error("用戶未登錄!"));
            response.getWriter().write(value);
        }
    }
}

SpringContextUtils工具類

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

/**
 * @Description: 用于創(chuàng)建上下文,實(shí)現(xiàn)ApplicationContextAware接口
 * @Author: 翰戈.summer
 * @Date: 2023/11/17
 * @Param:
 * @Return:
 */
@Component
public class SpringContextUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @Override
    public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException {
        SpringContextUtils.applicationContext = applicationContext;
    }

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException {
        if (applicationContext == null) {
            return null;
        }
        return (T) applicationContext.getBean(name);
    }
}

添加自定義token驗(yàn)證過濾器

將自定義token驗(yàn)證過濾器,添加到UsernamePasswordAuthenticationFilter前面。

UsernamePasswordAuthenticationFilter實(shí)現(xiàn)了基于用戶名和密碼的認(rèn)證邏輯,我們利用token進(jìn)行身份驗(yàn)證,所以用不到這個(gè)過濾器。

    /**
     * @Description: 配置SecurityFilterChain過濾器鏈
     * @Author: 翰戈.summer
     * @Date: 2023/11/17
     * @Param: HttpSecurity
     * @Return: SecurityFilterChain
     */
    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
                .requestMatchers(HttpMethod.POST, "/api/user/login").permitAll() //登錄放行
                .anyRequest().authenticated()
        );
        httpSecurity.authenticationProvider(authenticationProvider());

        //禁用登錄頁面
        httpSecurity.formLogin(AbstractHttpConfigurer::disable);
        //禁用登出頁面
        httpSecurity.logout(AbstractHttpConfigurer::disable);
        //禁用session
        httpSecurity.sessionManagement(AbstractHttpConfigurer::disable);
        //禁用httpBasic
        httpSecurity.httpBasic(AbstractHttpConfigurer::disable);
        //禁用csrf保護(hù)
        httpSecurity.csrf(AbstractHttpConfigurer::disable);

        //通過上下文獲取AuthenticationManager
        AuthenticationManager authenticationManager = SpringContextUtils.getBean("authenticationManager");
        //添加自定義token驗(yàn)證過濾器
        httpSecurity.addFilterBefore(new JwtAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class);

        return httpSecurity.build();
    }

自定義用戶未登錄的處理

用戶請(qǐng)求未攜帶token的處理,替換AuthenticationEntryPoint

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @Description: 自定義用戶未登錄的處理(未攜帶token)
 * @Author: 翰戈.summer
 * @Date: 2023/11/19
 * @Param:
 * @Return:
 */
@Component
public class AuthEntryPointHandler implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        String value = new ObjectMapper().writeValueAsString(Result.error("未攜帶token!"));
        response.getWriter().write(value);
    }
}

自定義用戶權(quán)限不足的處理

用戶權(quán)限不足的處理,替換AccessDeniedHandler

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @Description: 自定義用戶權(quán)限不足的處理
 * @Author: 翰戈.summer
 * @Date: 2023/11/19
 * @Param:
 * @Return:
 */
@Component
public class AuthAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        String value = new ObjectMapper().writeValueAsString(Result.error("權(quán)限不足!"));
        response.getWriter().write(value);
    }
}

添加自定義處理器

修改 SecurityConfig 配置類,注入 AuthAccessDeniedHandler 和 AuthEntryPointHandler

    /**
     * @Description: 配置SecurityFilterChain過濾器鏈
     * @Author: 翰戈.summer
     * @Date: 2023/11/17
     * @Param: HttpSecurity
     * @Return: SecurityFilterChain
     */
    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
                .requestMatchers(HttpMethod.POST, "/api/user/login").permitAll() //登錄放行
                .anyRequest().authenticated()
        );
        httpSecurity.authenticationProvider(authenticationProvider());

        //禁用登錄頁面
        httpSecurity.formLogin(AbstractHttpConfigurer::disable);
        //禁用登出頁面
        httpSecurity.logout(AbstractHttpConfigurer::disable);
        //禁用session
        httpSecurity.sessionManagement(AbstractHttpConfigurer::disable);
        //禁用httpBasic
        httpSecurity.httpBasic(AbstractHttpConfigurer::disable);
        //禁用csrf保護(hù)
        httpSecurity.csrf(AbstractHttpConfigurer::disable);

        //通過上下文獲取AuthenticationManager
        AuthenticationManager authenticationManager = SpringContextUtils.getBean("authenticationManager");
        //添加自定義token驗(yàn)證過濾器
        httpSecurity.addFilterBefore(new JwtAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class);

        //自定義處理器
        httpSecurity.exceptionHandling(exceptionHandling -> exceptionHandling
                .accessDeniedHandler(authAccessDeniedHandler) //處理用戶權(quán)限不足
                .authenticationEntryPoint(authEntryPointHandler) //處理用戶未登錄(未攜帶token)
        );

        return httpSecurity.build();
    }

靜態(tài)資源放行

SpringBoot3 中使用 Swagger3 接口文檔,在整合了 SpringSecurity 后會(huì)出現(xiàn)無法訪問的情況,需要給靜態(tài)資源放行。

在 SecurityConfig 中添加

    /**
     * 靜態(tài)資源放行
     */
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers(
                "/doc.html",
                "/doc.html/**",
                "/v3/api-docs",
                "/v3/api-docs/**",
                "/webjars/**",
                "/authenticate",
                "/swagger-ui.html/**",
                "/swagger-resources",
                "/swagger-resources/**"
        );
    }

總結(jié)

SpringSecurity6 的用法和以前版本的有較大差別,比如WebSecurityConfigurerAdapter的廢除,看到配置類繼承了這個(gè)的都是過時(shí)的教程。因?yàn)椴辉倮^承,所以不能通過重寫方法的方式去配置。另外很多配置的方式都變成使用Lambda表達(dá)式,或者是方法引用。

到此這篇關(guān)于SpringBoot3+SpringSecurity6前后端分離的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)SpringBoot3+SpringSecurity6前后端分離內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA中Spring Initializr沒有Java8選項(xiàng)的解決辦法

    IDEA中Spring Initializr沒有Java8選項(xiàng)的解決辦法

    在使用IDEA中的Spring Initializr創(chuàng)建新項(xiàng)目時(shí),Java 版本近可選擇Java17,21 ,不能選擇Java8;SpringBoot 版本也只有 3.x,所以本文給大家介紹了IDEA中Spring Initializr沒有Java8選項(xiàng)的解決辦法,需要的朋友可以參考下
    2024-06-06
  • SpringBoot跨域Jsonp和Cors的方法

    SpringBoot跨域Jsonp和Cors的方法

    這篇文章主要介紹了SpringBoot跨域Jsonp和Cors的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Java中的LinkedHashSet解析

    Java中的LinkedHashSet解析

    這篇文章主要介紹了Java中的LinkedHashSet解析,與HashSet不同的是,LinkedHashSet在內(nèi)部使用了一個(gè)雙向鏈表來維護(hù)元素的順序,因此它可以保持元素的插入順序,這使得LinkedHashSet在需要保持元素順序的場(chǎng)景下非常有用,需要的朋友可以參考下
    2023-11-11
  • SpringBoot的依賴管理配置

    SpringBoot的依賴管理配置

    一般來講SpringBoot項(xiàng)目是不需要指定版本,而SSM項(xiàng)目是需要指定版本,SpringBoot的核心依賴就是spring-boot-starter-parent和spring-boot-starter-web兩個(gè)依賴,關(guān)于這兩個(gè)依賴的相關(guān)介紹具體今天小編給大家介紹下
    2022-07-07
  • 基于SpringBoot框架管理Excel和PDF文件類型

    基于SpringBoot框架管理Excel和PDF文件類型

    這篇文章主要介紹了基于SpringBoot框架,管理Excel和PDF文件類型,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 一步步教你寫一個(gè)SpringMVC框架

    一步步教你寫一個(gè)SpringMVC框架

    現(xiàn)在主流的Web MVC框架除了Struts這個(gè)主力外,其次就是Spring MVC了,因此這也是作為一名程序員需要掌握的主流框架,這篇文章主要給大家介紹了關(guān)于如何一步步寫一個(gè)SpringMVC框架的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • Spring Boot + MyBatis Plus 高效開發(fā)實(shí)戰(zhàn)從入門到進(jìn)階優(yōu)化(推薦)

    Spring Boot + MyBatis Plus 高效開發(fā)實(shí)戰(zhàn)從入

    本文將詳細(xì)介紹 Spring Boot + MyBatis Plus 的完整開發(fā)流程,并深入剖析分頁查詢、批量操作、動(dòng)態(tài) SQL、樂觀鎖、代碼優(yōu)化等實(shí)戰(zhàn)技巧,感興趣的朋友一起看看吧
    2025-04-04
  • Mybatis如何傳入多個(gè)參數(shù)(實(shí)體類型和基本類型)

    Mybatis如何傳入多個(gè)參數(shù)(實(shí)體類型和基本類型)

    這篇文章主要介紹了Mybatis如何傳入多個(gè)參數(shù)(實(shí)體類型和基本類型),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • JVM---jstack分析Java線程CPU占用,線程死鎖的解決

    JVM---jstack分析Java線程CPU占用,線程死鎖的解決

    這篇文章主要介紹了JVM---jstack分析Java線程CPU占用,線程死鎖的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Java的線程與進(jìn)程以及線程的四種創(chuàng)建方式

    Java的線程與進(jìn)程以及線程的四種創(chuàng)建方式

    這篇文章主要為大家詳細(xì)介紹了Java的線程與進(jìn)程以及線程的四種創(chuàng)建方式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03

最新評(píng)論