最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot集成Spring Security用JWT令牌實(shí)現(xiàn)登錄和鑒權(quán)的方法

 更新時(shí)間:2020年05月17日 11:38:16   作者:Piconjo_Official  
這篇文章主要介紹了SpringBoot集成Spring Security用JWT令牌實(shí)現(xiàn)登錄和鑒權(quán)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

最近在做項(xiàng)目的過(guò)程中 需要用JWT做登錄和鑒權(quán) 查了很多資料 都不甚詳細(xì)
有的是需要在application.yml里進(jìn)行jwt的配置 但我在導(dǎo)包后并沒(méi)有相應(yīng)的配置項(xiàng) 因而并不適用
在踩過(guò)很多坑之后 稍微整理了一下 做個(gè)筆記

一、概念

1、什么是JWT

Json Web Token (JWT)是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開(kāi)放標(biāo)準(zhǔn)(RFC 7519)
該token被設(shè)計(jì)為緊湊且安全的 特別適用于分布式站點(diǎn)的單點(diǎn)登錄(SSO)場(chǎng)景

隨著JWT的出現(xiàn) 使得校驗(yàn)方式更加簡(jiǎn)單便捷化
JWT實(shí)際上就是一個(gè)字符串 它由三部分組成:頭部 載荷和簽名
用[.]分隔這三個(gè)部分 最終的格式類(lèi)似于:xxxx.xxxx.xxxx

在服務(wù)器直接根據(jù)token取出保存的用戶(hù)信息 即可對(duì)token的可用性進(jìn)行校驗(yàn) 使得單點(diǎn)登錄更為簡(jiǎn)單

2、JWT校驗(yàn)的過(guò)程

1、瀏覽器發(fā)送用戶(hù)名和密碼 發(fā)起登錄請(qǐng)求
2、服務(wù)端驗(yàn)證身份 根據(jù)算法將用戶(hù)標(biāo)識(shí)符打包生成token字符串 并且返回給瀏覽器
3、當(dāng)瀏覽器需要發(fā)起請(qǐng)求時(shí) 將token一起發(fā)送給服務(wù)器
4、服務(wù)器發(fā)現(xiàn)數(shù)據(jù)中攜帶有token 隨即進(jìn)行解密和鑒權(quán)
5、校驗(yàn)成功 服務(wù)器返回請(qǐng)求的數(shù)據(jù)

二、使用

1、首先是導(dǎo)包

<!-- Spring Security -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- Spring Security和JWT整合 -->
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-jwt</artifactId>
	<version>1.0.10.RELEASE</version>
</dependency>

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

<!-- 字符串轉(zhuǎn)換需要用到此包 -->
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-lang3</artifactId>
	<version>3.4</version>
</dependency>

2、實(shí)體類(lèi)

兩個(gè)實(shí)體類(lèi) 一個(gè)是用戶(hù) 另一個(gè)是權(quán)限

public class User {
  private Integer id;
  private String username;
  private String password;
  
	省略gettersetter之類(lèi)的代碼...
}
public class Role {
  private Integer id;
  private String username;
  private String name;
  
	省略gettersetter之類(lèi)的代碼...
}

3、然后需要一個(gè)Utils工具類(lèi)

該類(lèi)用于進(jìn)行Token的加密和解密 可在此類(lèi)中單元測(cè)試

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

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

public class JwtTokenUtil {
  // Token請(qǐng)求頭
  public static final String TOKEN_HEADER = "Authorization";
  // Token前綴
  public static final String TOKEN_PREFIX = "Bearer ";

  // 簽名主題
  public static final String SUBJECT = "piconjo";
  // 過(guò)期時(shí)間
  public static final long EXPIRITION = 1000 * 24 * 60 * 60 * 7;
  // 應(yīng)用密鑰
  public static final String APPSECRET_KEY = "piconjo_secret";
  // 角色權(quán)限聲明
  private static final String ROLE_CLAIMS = "role";
  
  /**
   * 生成Token
   */
  public static String createToken(String username,String role) {
    Map<String,Object> map = new HashMap<>();
    map.put(ROLE_CLAIMS, role);

    String token = Jwts
        .builder()
        .setSubject(username)
        .setClaims(map)
        .claim("username",username)
        .setIssuedAt(new Date())
        .setExpiration(new Date(System.currentTimeMillis() + EXPIRITION))
        .signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact();
    return token;
  }

  /**
   * 校驗(yàn)Token
   */
  public static Claims checkJWT(String token) {
    try {
      final Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
      return claims;
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }

  /**
   * 從Token中獲取username
   */
  public static String getUsername(String token){
    Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
    return claims.get("username").toString();
  }

  /**
   * 從Token中獲取用戶(hù)角色
   */
  public static String getUserRole(String token){
    Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
    return claims.get("role").toString();
  }

  /**
   * 校驗(yàn)Token是否過(guò)期
   */
  public static boolean isExpiration(String token){
    Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
    return claims.getExpiration().before(new Date());
  }
}

4、配置UserDetailsService的實(shí)現(xiàn)類(lèi) 用于加載用戶(hù)信息

import xxx.xxx.xxx.bean.Role; // 自己的包
import xxx.xxx.xxx.bean.User; // 自己的包
import xxx.xxx.xxx.mapper.UserMapper; // 自己的包
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.ArrayList;
import java.util.List;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

  @Autowired
  private UserMapper userMapper;

  @Override
  public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    if (s == null || "".equals(s))
    {
      throw new RuntimeException("用戶(hù)不能為空");
    }
    // 調(diào)用方法查詢(xún)用戶(hù)
    User user = userMapper.findUserByUsername(s);
    if (user == null)
    {
      throw new RuntimeException("用戶(hù)不存在");
    }
    List<SimpleGrantedAuthority> authorities = new ArrayList<>();
    for (Role role:userMapper.findRoleByUsername(s))
    {
      authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName()));
    }
    return new org.springframework.security.core.userdetails.User(user.getUsername(),"{noop}"+user.getPassword(),authorities);
  }
}

5、然后 配置兩個(gè)攔截器

其中 一個(gè)用于登錄 另一個(gè)用于鑒權(quán)

JWTAuthenticationFilter登錄攔截器:

該攔截器用于獲取用戶(hù)登錄的信息
至于具體的驗(yàn)證 只需創(chuàng)建一個(gè)token并調(diào)用authenticationManager的authenticate()方法
讓Spring security驗(yàn)證即可 驗(yàn)證的事交給框架

import com.alibaba.fastjson.JSON;
import xxx.xxx.xxx.utils.JwtTokenUtil; // 自己的包
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

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.Collection;

/**
 * 驗(yàn)證用戶(hù)名密碼正確后 生成一個(gè)token并將token返回給客戶(hù)端
 */
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

  private AuthenticationManager authenticationManager;

  public JWTAuthenticationFilter(AuthenticationManager authenticationManager)
  {
    this.authenticationManager = authenticationManager;
  }

  /**
   * 驗(yàn)證操作 接收并解析用戶(hù)憑證
   */
  @Override
  public Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException {
    // 從輸入流中獲取到登錄的信息
    // 創(chuàng)建一個(gè)token并調(diào)用authenticationManager.authenticate() 讓Spring security進(jìn)行驗(yàn)證
    return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(request.getParameter("username"),request.getParameter("password")));
  }

  /**
   * 驗(yàn)證【成功】后調(diào)用的方法
   * 若驗(yàn)證成功 生成token并返回
   */
  @Override
  protected void successfulAuthentication(HttpServletRequest request,HttpServletResponse response,FilterChain chain,Authentication authResult) throws IOException {
    User user= (User) authResult.getPrincipal();

    // 從User中獲取權(quán)限信息
    Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
    // 創(chuàng)建Token
    String token = JwtTokenUtil.createToken(user.getUsername(), authorities.toString());

    // 設(shè)置編碼 防止亂碼問(wèn)題
    response.setCharacterEncoding("UTF-8");
    response.setContentType("application/json; charset=utf-8");
    // 在請(qǐng)求頭里返回創(chuàng)建成功的token
    // 設(shè)置請(qǐng)求頭為帶有"Bearer "前綴的token字符串
    response.setHeader("token", JwtTokenUtil.TOKEN_PREFIX + token);

    // 處理編碼方式 防止中文亂碼
    response.setContentType("text/json;charset=utf-8");
    // 將反饋塞到HttpServletResponse中返回給前臺(tái)
    response.getWriter().write(JSON.toJSONString("登錄成功"));
  }

  /**
   * 驗(yàn)證【失敗】調(diào)用的方法
   */
  @Override
  protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
    String returnData="";
    // 賬號(hào)過(guò)期
    if (failed instanceof AccountExpiredException) {
      returnData="賬號(hào)過(guò)期";
    }
    // 密碼錯(cuò)誤
    else if (failed instanceof BadCredentialsException) {
      returnData="密碼錯(cuò)誤";
    }
    // 密碼過(guò)期
    else if (failed instanceof CredentialsExpiredException) {
      returnData="密碼過(guò)期";
    }
    // 賬號(hào)不可用
    else if (failed instanceof DisabledException) {
      returnData="賬號(hào)不可用";
    }
    //賬號(hào)鎖定
    else if (failed instanceof LockedException) {
      returnData="賬號(hào)鎖定";
    }
    // 用戶(hù)不存在
    else if (failed instanceof InternalAuthenticationServiceException) {
      returnData="用戶(hù)不存在";
    }
    // 其他錯(cuò)誤
    else{
      returnData="未知異常";
    }

    // 處理編碼方式 防止中文亂碼
    response.setContentType("text/json;charset=utf-8");
    // 將反饋塞到HttpServletResponse中返回給前臺(tái)
    response.getWriter().write(JSON.toJSONString(returnData));
  }
}

JWTAuthorizationFilter權(quán)限校驗(yàn)攔截器:

當(dāng)訪問(wèn)需要權(quán)限校驗(yàn)的URL(當(dāng)然 該URL也是需要經(jīng)過(guò)配置的) 則會(huì)來(lái)到此攔截器 在該攔截器中對(duì)傳來(lái)的Token進(jìn)行校驗(yàn)
只需告訴Spring security該用戶(hù)是否已登錄 并且是什么角色 擁有什么權(quán)限即可

import xxx.xxx.xxx.utils.JwtTokenUtil; // 自己的包
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

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.ArrayList;
import java.util.Collection;

/**
 * 登錄成功后 走此類(lèi)進(jìn)行鑒權(quán)操作
 */
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {

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

  /**
   * 在過(guò)濾之前和之后執(zhí)行的事件
   */
  @Override
  protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws IOException, ServletException {
    String tokenHeader = request.getHeader(JwtTokenUtil.TOKEN_HEADER);

    // 若請(qǐng)求頭中沒(méi)有Authorization信息 或是Authorization不以Bearer開(kāi)頭 則直接放行
    if (tokenHeader == null || !tokenHeader.startsWith(JwtTokenUtil.TOKEN_PREFIX))
    {
      chain.doFilter(request, response);
      return;
    }

    // 若請(qǐng)求頭中有token 則調(diào)用下面的方法進(jìn)行解析 并設(shè)置認(rèn)證信息
    SecurityContextHolder.getContext().setAuthentication(getAuthentication(tokenHeader));
    super.doFilterInternal(request, response, chain);
  }

  /**
   * 從token中獲取用戶(hù)信息并新建一個(gè)token
   *
   * @param tokenHeader 字符串形式的Token請(qǐng)求頭
   * @return 帶用戶(hù)名和密碼以及權(quán)限的Authentication
   */
  private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) {
    // 去掉前綴 獲取Token字符串
    String token = tokenHeader.replace(JwtTokenUtil.TOKEN_PREFIX, "");
    // 從Token中解密獲取用戶(hù)名
    String username = JwtTokenUtil.getUsername(token);
    // 從Token中解密獲取用戶(hù)角色
    String role = JwtTokenUtil.getUserRole(token);
    // 將[ROLE_XXX,ROLE_YYY]格式的角色字符串轉(zhuǎn)換為數(shù)組
    String[] roles = StringUtils.strip(role, "[]").split(", ");
    Collection<SimpleGrantedAuthority> authorities=new ArrayList<>();
    for (String s:roles)
    {
      authorities.add(new SimpleGrantedAuthority(s));
    }
    if (username != null)
    {
      return new UsernamePasswordAuthenticationToken(username, null,authorities);
    }
    return null;
  }
}

6、再配置一個(gè)自定義類(lèi) 用于進(jìn)行匿名用戶(hù)訪問(wèn)資源時(shí)無(wú)權(quán)限的處理

該類(lèi)需實(shí)現(xiàn)AuthenticationEntryPoint

import com.alibaba.fastjson.JSONObject;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

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

public class JWTAuthenticationEntryPoint implements AuthenticationEntryPoint {

  @Override
  public void commence(HttpServletRequest request, HttpServletResponse response,
             AuthenticationException authException) throws IOException, ServletException {
    response.setCharacterEncoding("utf-8");
    response.setContentType("text/javascript;charset=utf-8");
    response.getWriter().print(JSONObject.toJSONString("您未登錄,沒(méi)有訪問(wèn)權(quán)限"));
  }
}

7、最后 將這些組件組裝到一起即可

創(chuàng)建一個(gè)自定義的配置類(lèi) 繼承WebSecurityConfigurerAdapter
在該類(lèi)上 需加@EnableWebSecurity注解 配置Web安全過(guò)濾器和啟用全局認(rèn)證機(jī)制

import xxx.xxx.xxx.JWTAuthenticationEntryPoint; // 自己的包
import xxx.xxx.xxx.xxx.JWTAuthenticationFilter; // 自己的包
import xxx.xxx.xxx.xxx.JWTAuthorizationFilter; // 自己的包
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  @Qualifier("userDetailsServiceImpl")
  private UserDetailsService userDetailsService;

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService);
  }

  /**
   * 安全配置
   */
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    // 跨域共享
    http.cors()
        .and()
        // 跨域偽造請(qǐng)求限制無(wú)效
        .csrf().disable()
        .authorizeRequests()
        // 訪問(wèn)/data需要ADMIN角色
        .antMatchers("/data").hasRole("ADMIN")
        // 其余資源任何人都可訪問(wèn)
        .anyRequest().permitAll()
        .and()
        // 添加JWT登錄攔截器
        .addFilter(new JWTAuthenticationFilter(authenticationManager()))
        // 添加JWT鑒權(quán)攔截器
        .addFilter(new JWTAuthorizationFilter(authenticationManager()))
        .sessionManagement()
        // 設(shè)置Session的創(chuàng)建策略為:Spring Security永不創(chuàng)建HttpSession 不使用HttpSession來(lái)獲取SecurityContext
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        // 異常處理
        .exceptionHandling()
        // 匿名用戶(hù)訪問(wèn)無(wú)權(quán)限資源時(shí)的異常
        .authenticationEntryPoint(new JWTAuthenticationEntryPoint());
  }

  /**
   * 跨域配置
   * @return 基于URL的跨域配置信息
   */
  @Bean
  CorsConfigurationSource corsConfigurationSource() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    // 注冊(cè)跨域配置
    source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
    return source;
  }
}

定義一個(gè)用于測(cè)試的對(duì)外映射接口:

@RestController
public class UserController {

  @GetMapping("/data")
  private ResponseUtil data()
  {
    return "This is data.";
  }
}

默認(rèn)登錄路徑是/login 用POST請(qǐng)求發(fā)送

若要修改默認(rèn)的登錄路徑 只需要在自己定義的登錄過(guò)濾器JWTAuthenticationFilter的構(gòu)造方法里進(jìn)行配置即可
比如 若想修改為/api/login:

public JWTAuthenticationFilter(AuthenticationManager authenticationManager)
{
   this.authenticationManager = authenticationManager;
   // 設(shè)置登錄URL
   super.setFilterProcessesUrl("/api/login");
}

登錄時(shí) 參數(shù)的屬性名分別是username和password 不能改動(dòng):

登錄成功后會(huì)返回一個(gè)Token:

在請(qǐng)求需要權(quán)限的接口路徑時(shí) 若不帶上Token 則會(huì)提示沒(méi)有訪問(wèn)權(quán)限

帶上Token后再次請(qǐng)求 即可正常訪問(wèn):

注:Token的前面要帶有Bearer 的前綴


這樣 一個(gè)基本的實(shí)現(xiàn)就差不多完成了

為簡(jiǎn)單演示 在該案例中就不對(duì)密碼進(jìn)行加密了 實(shí)際開(kāi)發(fā)是需要對(duì)明文密碼加密后存儲(chǔ)的 推薦用BCrypt進(jìn)行加密和解密
為節(jié)省篇幅 用于注冊(cè)的接口也不寫(xiě)了 實(shí)際上在注冊(cè)接口傳入的密碼也需要用BCrypt加密后再存入數(shù)據(jù)庫(kù)中
還可以用Redis進(jìn)行Token的存儲(chǔ) 這些都是后話了

到此這篇關(guān)于SpringBoot集成Spring Security用JWT令牌實(shí)現(xiàn)登錄和鑒權(quán)的方法的文章就介紹到這了,更多相關(guān)SpringBoot JWT令牌登錄和鑒權(quán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot?publish?event?事件機(jī)制demo分享

    springboot?publish?event?事件機(jī)制demo分享

    這篇文章主要介紹了springboot?publish?event?事件機(jī)制demo,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Java并發(fā)編程中的生產(chǎn)者與消費(fèi)者模型簡(jiǎn)述

    Java并發(fā)編程中的生產(chǎn)者與消費(fèi)者模型簡(jiǎn)述

    這篇文章主要介紹了Java并發(fā)編程中的生產(chǎn)者與消費(fèi)者模型簡(jiǎn)述,多線程并發(fā)是Java編程中最終要的部分之一,需要的朋友可以參考下
    2015-07-07
  • Ribbon從入門(mén)到精通實(shí)戰(zhàn)案例演示

    Ribbon從入門(mén)到精通實(shí)戰(zhàn)案例演示

    Ribbon是Netflix開(kāi)源的客戶(hù)端負(fù)載均衡工具,用于微服務(wù)通信,動(dòng)態(tài)獲取服務(wù)實(shí)例并應(yīng)用輪詢(xún)、隨機(jī)、權(quán)重響應(yīng)時(shí)間等策略,下面通過(guò)實(shí)戰(zhàn)案例給大家解析Ribbon的核心組件與工作原理,感興趣的朋友一起看看吧
    2025-08-08
  • Mybatis?在?insert?插入操作后返回主鍵?id的操作方法

    Mybatis?在?insert?插入操作后返回主鍵?id的操作方法

    這篇文章主要介紹了Mybatis?在?insert?插入操作后返回主鍵?id的操作方法,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • MyBatis 中  type-aliases-package的作用(簡(jiǎn)化類(lèi)型映射)

    MyBatis 中  type-aliases-package的作用(簡(jiǎn)化類(lèi)型映射)

    MyBatis中type-aliases-package的作用是簡(jiǎn)化類(lèi)型映射,通過(guò)指定包路徑,MyBatis會(huì)自動(dòng)掃描該包下的所有類(lèi)并為這些類(lèi)生成類(lèi)型別名,減少XML配置文件中的冗長(zhǎng)代碼,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • mybatis創(chuàng)建一個(gè)或多個(gè)新用戶(hù) insert 字段和表名不確定時(shí)動(dòng)態(tài)添加問(wèn)題

    mybatis創(chuàng)建一個(gè)或多個(gè)新用戶(hù) insert 字段和表名不確定時(shí)動(dòng)態(tài)添加問(wèn)題

    這篇文章主要介紹了mybatis創(chuàng)建一個(gè)或多個(gè)新用戶(hù) insert 字段和表名不確定時(shí)動(dòng)態(tài)添加問(wèn)題,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-02-02
  • Spring Security實(shí)現(xiàn)退出登錄和退出處理器

    Spring Security實(shí)現(xiàn)退出登錄和退出處理器

    本文主要介紹了Spring Security實(shí)現(xiàn)退出登錄和退出處理器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • Java編寫(xiě)日志手機(jī)號(hào)脫敏工具類(lèi)

    Java編寫(xiě)日志手機(jī)號(hào)脫敏工具類(lèi)

    在開(kāi)發(fā)過(guò)程中,很容易將用戶(hù)敏感信息,例如手機(jī)號(hào)碼、身份證等,打印在日志平臺(tái),本文將利用Java編寫(xiě)一個(gè)日志手機(jī)號(hào)脫敏工具類(lèi),感興趣的可以了解下
    2024-12-12
  • 如何使用IntelliJ?IDEA寫(xiě)一個(gè)簡(jiǎn)單的JSP網(wǎng)頁(yè)

    如何使用IntelliJ?IDEA寫(xiě)一個(gè)簡(jiǎn)單的JSP網(wǎng)頁(yè)

    目前市場(chǎng)上流傳很多jsp項(xiàng)目,雖然是很老的項(xiàng)目,但是對(duì)于畢業(yè)設(shè)計(jì)項(xiàng)目來(lái)說(shuō)還是很好的學(xué)習(xí)項(xiàng)目,下面這篇文章主要介紹了如何使用IntelliJ?IDEA寫(xiě)一個(gè)簡(jiǎn)單的JSP網(wǎng)頁(yè),需要的朋友可以參考下
    2025-07-07
  • Spring Bean的包掃描的實(shí)現(xiàn)方法

    Spring Bean的包掃描的實(shí)現(xiàn)方法

    這篇文章主要介紹了Spring Bean的包掃描的實(shí)現(xiàn)方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01

最新評(píng)論

商都县| 大丰市| 潞城市| 于都县| 嘉善县| 阿拉善左旗| 台东市| 肇源县| 读书| 纳雍县| 荆门市| 上犹县| 乐亭县| 吉隆县| 枣阳市| 荥经县| 凌源市| 志丹县| 铜鼓县| 海原县| 即墨市| 陆良县| 白山市| 梁河县| 潮州市| 顺昌县| 德格县| 河北省| 诸暨市| 个旧市| 荥经县| 承德市| 枣庄市| 绵竹市| 专栏| 马鞍山市| 宝坻区| 朝阳县| 岱山县| 泰和县| 福鼎市|