目次
ナレッジポイント補足
白キャッシュ
プロセス分析
Shiro セッション メカニズム
統合手順
キャッシュの追加
CacheManager
Shiro のデフォルトの EhCache 実装を使用する
hiro-EhCache 依存関係の紹介
ShiroConfig にキャッシュ構成を追加します
Redis を使用して実装します
依存関係を追加します
redis を構成します
保護されたリソースへのアクセス
表示 の 3 つの主要な値redis
ホームページ Java &#&チュートリアル Springboot が認証と動的権限管理を実装する方法

Springboot が認証と動的権限管理を実装する方法

Jun 03, 2023 pm 09:46 PM
springboot

ナレッジポイント補足

白キャッシュ

プロセス分析

元のプロジェクトではキャッシュが設定されていないため、現在の対象が毎回のアクセス権 毎回、データベースがクエリされます。権限データは通常、読み取りが多く書き込みが少ないデータであるため、それにキャッシュのサポートを追加する必要があります。

キャッシュを追加すると、Shiro は認証時にまずキャッシュに関連データをクエリします。キャッシュにデータがない場合はデータベースにクエリを実行し、見つかったデータをキャッシュに書き込みます。チェックされると、キャッシュから取得できるようになり、データベースからではなくキャッシュからデータを取得します。これにより、アプリケーションのパフォーマンスが向上します。

次に、hiroのキャッシュ管理部分を実装してみましょう。

Shiro セッション メカニズム

Shiro は、基礎となるコンテナ (Web コンテナ Tomcat など) に依存しない、完全なエンタープライズ レベルのセッション管理機能を提供します。 JavaEE 環境では、セッション管理、セッション イベントの監視、セッションのストレージ/永続化、コンテナに依存しないクラスタリング、無効化/有効期限のサポート、Web の透過的なサポート、SSO シングル サインオンのサポートなどの機能が提供されます。

Shiro のセッション管理を使用して、アプリケーションの Web セッションを引き継ぎ、Redis を通じてセッション情報を保存します。

統合手順

キャッシュの追加

CacheManager

Shiro では、キャッシュ管理のための CacheManager クラスが提供されています。

Shiro のデフォルトの EhCache 実装を使用する

Shiro では、EhCache キャッシュ フレームワークがデフォルトで使用されます。 EhCache は、高速で無駄のない純粋な Java インプロセス キャッシュ フレームワークです。

hiro-EhCache 依存関係の紹介
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.4.0</version>
</dependency>
ログイン後にコピー

Redis と SpringBoot を統合するプロセスでは、バージョンの一致の問題にも注意する必要があります。そうしないと、メソッドが見つからないという例外が報告される可能性があります。

ShiroConfig にキャッシュ構成を追加します
private void enableCache(MySQLRealm realm){
    //开启全局缓存配置
    realm.setCachingEnabled(true);
    //开启认证缓存配置
    realm.setAuthenticationCachingEnabled(true);
    //开启授权缓存配置
    realm.setAuthorizationCachingEnabled(true);

    //为了方便操作,我们给缓存起个名字
    realm.setAuthenticationCacheName("authcCache");
    realm.setAuthorizationCacheName("authzCache");
    //注入缓存实现
    realm.setCacheManager(new EhCacheManager());
}
ログイン後にコピー

次に、getRealm でこのメソッドを呼び出します。

ヒント: この実装では、ローカル キャッシュのみが実装されます。つまり、キャッシュされたデータはアプリケーションと同じマシン メモリを共有します。サーバーがダウンしたり、予期しない停電が発生した場合、キャッシュされたデータは存在しなくなります。もちろん、cacheManager.setCacheManagerConfigFile() メソッドを使用して、キャッシュにさらに構成を与えることもできます。

次に、Redis を介して権限データをキャッシュします

Redis を使用して実装します

依存関係を追加します
<!--shiro-redis相关依赖-->
        <dependency>
            <groupId>org.crazycake</groupId>
            <artifactId>shiro-redis</artifactId>
            <version>3.1.0</version>
            <!--    里面这个shiro-core版本较低,会引发一个异常
					ClassNotFoundException: org.apache.shiro.event.EventBus
                    需要排除,直接使用上面的shiro
                    shiro1.3 加入了时间总线。-->
            <exclusions>
                <exclusion>
                    <groupId>org.apache.shiro</groupId>
                    <artifactId>shiro-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
ログイン後にコピー
redis を構成します

追加でredis 関連の設定を application.yml

spring:
   redis:
     host: 127.0.0.1
     port: 6379
     password: hewenping
     timeout: 3000
     jedis:
       pool:
         min-idle: 5
         max-active: 20
         max-idle: 15
ログイン後にコピー

ShiroConfig 設定クラスを変更し、hiro-redis プラグイン設定を追加します

/**shiro配置类
 * @author 赖柄沣 bingfengdev@aliyun.com
 * @version 1.0
 * @date 2020/10/6 9:11
 */
@Configuration
public class ShiroConfig {

    private static final String CACHE_KEY = "shiro:cache:";
    private static final String SESSION_KEY = "shiro:session:";
    private static final int EXPIRE = 18000;
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.redis.password}")
    private String password;

    @Value("${spring.redis.jedis.pool.min-idle}")
    private int minIdle;
    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.jedis.pool.max-active}")
    private int maxActive;

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


    /**
     * 创建ShiroFilter拦截器
     * @return ShiroFilterFactoryBean
     */
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //配置不拦截路径和拦截路径,顺序不能反
        HashMap<String, String> map = new HashMap<>(5);

        map.put("/authc/**","anon");
        map.put("/login.html","anon");
        map.put("/js/**","anon");
        map.put("/css/**","anon");

        map.put("/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        //覆盖默认的登录url
        shiroFilterFactoryBean.setLoginUrl("/authc/unauthc");
        return shiroFilterFactoryBean;
    }

    @Bean
    public Realm getRealm(){
        //设置凭证匹配器,修改为hash凭证匹配器
        HashedCredentialsMatcher myCredentialsMatcher = new HashedCredentialsMatcher();
        //设置算法
        myCredentialsMatcher.setHashAlgorithmName("md5");
        //散列次数
        myCredentialsMatcher.setHashIterations(1024);
        MySQLRealm realm = new MySQLRealm();
        realm.setCredentialsMatcher(myCredentialsMatcher);
        //开启缓存
        realm.setCachingEnabled(true);
        realm.setAuthenticationCachingEnabled(true);
        realm.setAuthorizationCachingEnabled(true);
        return realm;
    }

    /**
     * 创建shiro web应用下的安全管理器
     * @return DefaultWebSecurityManager
     */
    @Bean
    public DefaultWebSecurityManager getSecurityManager( Realm realm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
    
        securityManager.setCacheManager(cacheManager());
        SecurityUtils.setSecurityManager(securityManager);
        return securityManager;
    }



    /**
     * 配置Redis管理器
     * @Attention 使用的是shiro-redis开源插件
     * @return
     */
    @Bean
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        redisManager.setTimeout(timeout);
        redisManager.setPassword(password);
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(maxIdle+maxActive);
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        redisManager.setJedisPoolConfig(jedisPoolConfig);
        return redisManager;
    }


    @Bean
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        redisCacheManager.setKeyPrefix(CACHE_KEY);
        // shiro-redis要求放在session里面的实体类必须有个id标识
        //这是组成redis中所存储数据的key的一部分
        redisCacheManager.setPrincipalIdFieldName("username");
        return redisCacheManager;
    }

}
ログイン後にコピー

MySQLRealm# の doGetAuthenticationInfo## を変更しますメソッドでは、User オブジェクト全体を SimpleAuthenticationInfo の最初のパラメーターとして使用します。 hiro-redis は、RedisCacheManagerprincipalIdFieldName 属性値に基づいて、redis 内のデータのキーの一部として最初のパラメーターから id 値を取得します。

/**
 * 认证
 * @param token
 * @return
 * @throws AuthenticationException
 */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

    if(token==null){
        return null;
    }
    String principal = (String) token.getPrincipal();
    User user = userService.findByUsername(principal);
    SimpleAuthenticationInfo simpleAuthenticationInfo = new MyAuthcInfo(
            //由于shiro-redis插件需要从这个属性中获取id作为redis的key
            //所有这里传的是user而不是username
            user,
            //凭证信息
            user.getPassword(),
            //加密盐值
            new CurrentSalt(user.getSalt()),
            getName());
    
    return simpleAuthenticationInfo;
}
ログイン後にコピー

そして、

MySQLRealmdoGetAuthorizationInfo メソッドを変更して、User オブジェクトからプライマリ ID 情報を取得します。

/**
 * 授权
 * @param principals
 * @return
 */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
   User user = (User) principals.getPrimaryPrincipal();
    String username = user.getUsername();
    List<Role> roleList = roleService.findByUsername(username);
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    for (Role role : roleList) {
        authorizationInfo.addRole(role.getRoleName());
    }
    List<Long> roleIdList  = new ArrayList<>();
    for (Role role : roleList) {
        roleIdList.add(role.getRoleId());
    }

    List<Resource> resourceList = resourceService.findByRoleIds(roleIdList);
    for (Resource resource : resourceList) {
        authorizationInfo.addStringPermission(resource.getResourcePermissionTag());
    }
    return authorizationInfo;
}
ログイン後にコピー

カスタマイズされたソルト
Shiro のデフォルトの

SimpleByteSource はシリアル化インターフェイスを実装していないため、ByteSource.Util.bytes() によって生成されたソルトによりシリアル化中にエラーが発生します。したがって、Salt クラスをカスタマイズし、シリアル化インターフェイスを実装する必要があります。そして、new CurrentSalt(user.getSalt()) を使用して、カスタム Realm 認証メソッドにソルト値を渡します。

/**由于shiro当中的ByteSource没有实现序列化接口,缓存时会发生错误
 * 因此,我们需要通过自定义ByteSource的方式实现这个接口
 * @author 赖柄沣 bingfengdev@aliyun.com
 * @version 1.0
 * @date 2020/10/8 16:17
 */
public class CurrentSalt extends SimpleByteSource implements Serializable {
    public CurrentSalt(String string) {
        super(string);
    }

    public CurrentSalt(byte[] bytes) {
        super(bytes);
    }

    public CurrentSalt(char[] chars) {
        super(chars);
    }

    public CurrentSalt(ByteSource source) {
        super(source);
    }

    public CurrentSalt(File file) {
        super(file);
    }

    public CurrentSalt(InputStream stream) {
        super(stream);
    }
}
ログイン後にコピー

Shiro カスタム セッションの追加

カスタム セッション ID ジェネレーターの追加

/**SessionId生成器
 * <p>@author 赖柄沣 laibingf_dev@outlook.com</p>
 * <p>@date 2020/8/15 15:19</p>
 */
public class ShiroSessionIdGenerator implements SessionIdGenerator {

    /**
     *实现SessionId生成
     * @param session
     * @return
     */
    @Override
    public Serializable generateId(Session session) {
        Serializable sessionId = new JavaUuidSessionIdGenerator().generateId(session);
        return String.format("login_token_%s", sessionId);
    }
}
ログイン後にコピー

カスタム セッション マネージャーの追加

/**
 * <p>@author 赖柄沣 laibingf_dev@outlook.com</p>
 * <p>@date 2020/8/15 15:40</p>
 */
public class ShiroSessionManager extends DefaultWebSessionManager {

    //定义常量
    private static final String AUTHORIZATION = "Authorization";
    private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
    //重写构造器
    public ShiroSessionManager() {
        super();
        this.setDeleteInvalidSessions(true);
    }

    /**
     * 重写方法实现从请求头获取Token便于接口统一
     *      * 每次请求进来,
     *      Shiro会去从请求头找Authorization这个key对应的Value(Token)
     * @param request
     * @param response
     * @return
     */
    @Override
    public Serializable getSessionId(ServletRequest request, ServletResponse response) {
        String token = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
        //如果请求头中存在token 则从请求头中获取token
        if (!StringUtils.isEmpty(token)) {
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, token);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return token;
        } else {
            // 这里禁用掉Cookie获取方式
            return null;
        }
    }
}
ログイン後にコピー

カスタム セッション管理の構成

セッションマネージャーの設定をShiroConfigに追加します

/**
 * SessionID生成器
 *
 */
@Bean
public ShiroSessionIdGenerator sessionIdGenerator(){
    return new ShiroSessionIdGenerator();
}

/**
 * 配置RedisSessionDAO
 */
@Bean
public RedisSessionDAO redisSessionDAO() {
    RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
    redisSessionDAO.setRedisManager(redisManager());
    redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());
    redisSessionDAO.setKeyPrefix(SESSION_KEY);
    redisSessionDAO.setExpire(EXPIRE);
    return redisSessionDAO;
}

/**
 * 配置Session管理器
 * @Author Sans
 *
 */
@Bean
public SessionManager sessionManager() {
    ShiroSessionManager shiroSessionManager = new ShiroSessionManager();
    shiroSessionManager.setSessionDAO(redisSessionDAO());
    //禁用cookie
    shiroSessionManager.setSessionIdCookieEnabled(false);
    //禁用会话id重写
    shiroSessionManager.setSessionIdUrlRewritingEnabled(false);
    return shiroSessionManager;
}
ログイン後にコピー

最新バージョン(1.6.0)では、セッションマネージャーのsetSessionIdUrlRewritingEnabled(false)設定が有効にならず、直接認証されなくなります 複数のリダイレクトエラーが発生しました保護されたリソースにアクセスするとき。この不具合は、hiroのバージョンを1.5.0に変更したことで解決されました。

本来は昨夜投稿する予定だったこの記事ですが、諸事情により今日投稿するまでに時間がかかってしまいました。 。 。

カスタム レルムの doGetAuthenticationInfo 認証メソッドを変更します

認証情報が返される前に、次の判断を行う必要があります。現在のユーザーが古いデバイスにログインしている場合、そのセッションは古いデバイスはIDを削除してオフラインにする必要があります。

/**
 * 认证
 * @param token
 * @return
 * @throws AuthenticationException
 */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

    if(token==null){
        return null;
    }
    String principal = (String) token.getPrincipal();
    User user = userService.findByUsername(principal);
    SimpleAuthenticationInfo simpleAuthenticationInfo = new MyAuthcInfo(
            //由于shiro-redis插件需要从这个属性中获取id作为redis的key
            //所有这里传的是user而不是username
            user,
            //凭证信息
            user.getPassword(),
            //加密盐值
            new CurrentSalt(user.getSalt()),
            getName());

    //清除当前主体旧的会话,相当于你在新电脑上登录系统,把你之前在旧电脑上登录的会话挤下去
    ShiroUtils.deleteCache(user.getUsername(),true);
    return simpleAuthenticationInfo;
}
ログイン後にコピー

ログイン インターフェイスを変更する

セッション情報を Redis に保存し、ユーザーが認証された後、セッション ID をトークンの形式でユーザーに返します。ユーザーは保護されたリソースをリクエストする際にこのトークンを持参し、そのトークン情報を元にredisからユーザーの権限情報を取得し、アクセス制御を行います。

@PostMapping("/login")
public HashMap<Object, Object> login(@RequestBody LoginVO loginVO) throws AuthenticationException {
    boolean flags = authcService.login(loginVO);
    HashMap<Object, Object> map = new HashMap<>(3);
    if (flags){
        Serializable id = SecurityUtils.getSubject().getSession().getId();
        map.put("msg","登录成功");
        map.put("token",id);
        return map;
    }else {
        return null;
    } 
}
ログイン後にコピー

グローバル例外処理を追加

/**shiro异常处理
 * @author 赖柄沣 bingfengdev@aliyun.com
 * @version 1.0
 * @date 2020/10/7 18:01
 */
@ControllerAdvice(basePackages = "pers.lbf.springbootshiro")
public class AuthExceptionHandler {

    //==================认证异常====================//

    @ExceptionHandler(ExpiredCredentialsException.class)
    @ResponseBody
    public String expiredCredentialsExceptionHandlerMethod(ExpiredCredentialsException e) {
        return "凭证已过期";
    }

    @ExceptionHandler(IncorrectCredentialsException.class)
    @ResponseBody
    public String incorrectCredentialsExceptionHandlerMethod(IncorrectCredentialsException e) {
        return "用户名或密码错误";
    }

    @ExceptionHandler(UnknownAccountException.class)
    @ResponseBody
    public String unknownAccountExceptionHandlerMethod(IncorrectCredentialsException e) {
        return "用户名或密码错误";
    }

    
    @ExceptionHandler(LockedAccountException.class)
    @ResponseBody
    public String lockedAccountExceptionHandlerMethod(IncorrectCredentialsException e) {
        return "账户被锁定";
    }

    //=================授权异常=====================//

    @ExceptionHandler(UnauthorizedException.class)
    @ResponseBody
    public String unauthorizedExceptionHandlerMethod(UnauthorizedException e){
        return "未授权!请联系管理员授权";
    }
}
ログイン後にコピー
実際の開発では、返される結果を統一し、ビジネスエラーコードを付与する必要があります。この記事では説明しませんので、必要に応じて、ご自身のシステムの特性に応じて検討してください。

テスト

認証

ログイン成功

Springboot が認証と動的権限管理を実装する方法

ユーザー名またはパスワードが間違っています

Springboot が認証と動的権限管理を実装する方法

セキュリティ上の理由から、ユーザー名またはパスワードが間違っているかどうかは明らかにしないでください。

保護されたリソースへのアクセス

認証後の許可されたリソースへのアクセス

Springboot が認証と動的権限管理を実装する方法

認証後のアクセス許可されていないリソース

Springboot が認証と動的権限管理を実装する方法

認証なしの直接アクセス

Springboot が認証と動的権限管理を実装する方法

表示 の 3 つの主要な値redis

Springboot が認証と動的権限管理を実装する方法

は、それぞれ認証情報キャッシュ、認可情報キャッシュ、セッション情報キャッシュに対応します。

以上がSpringboot が認証と動的権限管理を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Springboot が Jasypt を統合して構成ファイルの暗号化を実装する方法 Springboot が Jasypt を統合して構成ファイルの暗号化を実装する方法 Jun 01, 2023 am 08:55 AM

Jasypt の概要 Jasypt は、開発者が最小限の労力で基本的な暗号化機能を自分のプロジェクトに追加できる Java ライブラリであり、暗号化の仕組みを深く理解する必要はありません。一方向および双方向暗号化の高いセキュリティ。標準ベースの暗号化テクノロジー。パスワード、テキスト、数値、バイナリを暗号化します... Spring ベースのアプリケーション、オープン API への統合、JCE プロバイダーでの使用に適しています... 次の依存関係を追加します: com.github.ulisesbocchiojasypt-spring-boot-starter2. 1.1 Jasypt の特典はシステムのセキュリティを保護し、コードが漏洩した場合でもデータ ソースは保証されます。

SpringBoot が Redisson を統合して遅延キューを実装する方法 SpringBoot が Redisson を統合して遅延キューを実装する方法 May 30, 2023 pm 02:40 PM

使用シナリオ 1. 注文は正常に行われましたが、支払いが 30 分以内に行われませんでした。支払いがタイムアウトになり、注文が自動的にキャンセルされました 2. 注文に署名があり、署名後 7 日間評価が行われませんでした。注文がタイムアウトして評価されない場合、システムはデフォルトでプラスの評価を設定します 3. 注文は正常に行われます。販売者が 5 分間注文を受け取らない場合、注文はキャンセルされます。 4. 配送がタイムアウトします。 SMS リマインダーをプッシュします... 遅延が長く、リアルタイム パフォーマンスが低いシナリオでは、タスク スケジュールを使用して定期的なポーリング処理を実行できます。例: xxl-job 今日は選択します

Redis を使用して SpringBoot に分散ロックを実装する方法 Redis を使用して SpringBoot に分散ロックを実装する方法 Jun 03, 2023 am 08:16 AM

1. Redis は分散ロックの原則を実装しており、分散ロックが必要な理由 分散ロックについて話す前に、分散ロックが必要な理由を説明する必要があります。分散ロックの反対はスタンドアロン ロックです。マルチスレッド プログラムを作成するとき、共有変数を同時に操作することによって引き起こされるデータの問題を回避します。通常、ロックを使用して共有変数を相互に除外し、データの正確性を確保します。共有変数の使用範囲は同じプロセス内です。共有リソースを同時に操作する必要があるプロセスが複数ある場合、どうすれば相互排他的になるのでしょうか?今日のビジネス アプリケーションは通常マイクロサービス アーキテクチャであり、これは 1 つのアプリケーションが複数のプロセスをデプロイすることも意味します。複数のプロセスが MySQL の同じレコード行を変更する必要がある場合、順序の乱れた操作によって引き起こされるダーティ データを避けるために、分散が必要です。今回導入するスタイルはロックされています。ポイントを獲得したい

Springbootがjarパッケージにファイルを読み込んだ後にファイルにアクセスできない問題を解決する方法 Springbootがjarパッケージにファイルを読み込んだ後にファイルにアクセスできない問題を解決する方法 Jun 03, 2023 pm 04:38 PM

Springboot はファイルを読み取りますが、jar パッケージにパッケージ化した後、最新の開発にアクセスできません。jar パッケージにパッケージ化した後、Springboot がファイルを読み取れない状況があります。その理由は、パッケージ化後、ファイルの仮想パスが変更されるためです。は無効であり、ストリーム経由でのみアクセスできます。読み取ります。ファイルはリソースの下にあります publicvoidtest(){Listnames=newArrayList();InputStreamReaderread=null;try{ClassPathResourceresource=newClassPathResource("name.txt");Input

SQL ステートメントを使用せずに Springboot+Mybatis-plus を実装して複数のテーブルを追加する方法 SQL ステートメントを使用せずに Springboot+Mybatis-plus を実装して複数のテーブルを追加する方法 Jun 02, 2023 am 11:07 AM

Springboot+Mybatis-plus が SQL ステートメントを使用して複数テーブルの追加操作を実行しない場合、私が遭遇した問題は、テスト環境で思考をシミュレートすることによって分解されます: パラメーターを含む BrandDTO オブジェクトを作成し、パラメーターをバックグラウンドに渡すことをシミュレートします。 Mybatis-plus で複数テーブルの操作を実行するのは非常に難しいことを理解してください。Mybatis-plus-join などのツールを使用しない場合は、対応する Mapper.xml ファイルを設定し、臭くて長い ResultMap を設定するだけです。対応する SQL ステートメントを記述します。この方法は面倒に見えますが、柔軟性が高く、次のことが可能です。

SpringBootとSpringMVCの比較と差異分析 SpringBootとSpringMVCの比較と差異分析 Dec 29, 2023 am 11:02 AM

SpringBoot と SpringMVC はどちらも Java 開発で一般的に使用されるフレームワークですが、それらの間には明らかな違いがいくつかあります。この記事では、これら 2 つのフレームワークの機能と使用法を調べ、その違いを比較します。まず、SpringBoot について学びましょう。 SpringBoot は、Spring フレームワークに基づいたアプリケーションの作成と展開を簡素化するために、Pivo​​tal チームによって開発されました。スタンドアロンの実行可能ファイルを構築するための高速かつ軽量な方法を提供します。

SpringBoot が Redis をカスタマイズしてキャッシュのシリアル化を実装する方法 SpringBoot が Redis をカスタマイズしてキャッシュのシリアル化を実装する方法 Jun 03, 2023 am 11:32 AM

1. RedisAPI のデフォルトのシリアル化メカニズムである RedisTemplate1.1 をカスタマイズします。API ベースの Redis キャッシュ実装では、データ キャッシュ操作に RedisTemplate テンプレートを使用します。ここで、RedisTemplate クラスを開いて、クラスのソース コード情報を表示します。publicclassRedisTemplateextendsRedisAccessorimplementsRedisOperations、BeanClassLoaderAware{//キーを宣言、値の各種シリアル化メソッド、初期値は空 @NullableprivateRedisSe

Springbootでapplication.ymlの値を取得する方法 Springbootでapplication.ymlの値を取得する方法 Jun 03, 2023 pm 06:43 PM

プロジェクトでは、構成情報が必要になることがよくありますが、この情報はテスト環境と本番環境で構成が異なる場合があり、実際のビジネス状況に基づいて後で変更する必要がある場合があります。これらの構成をコードにハードコーディングすることはできません。構成ファイルに記述することをお勧めします。たとえば、この情報を application.yml ファイルに書き込むことができます。では、コード内でこのアドレスを取得または使用するにはどうすればよいでしょうか?方法は2つあります。方法 1: @Value アノテーションが付けられた ${key} を介して、構成ファイル (application.yml) 内のキーに対応する値を取得できます。この方法は、マイクロサービスが比較的少ない状況に適しています。方法 2: 実際には、プロジェクト、業務が複雑な場合、ロジック

See all articles