Apache Shiro(一)

news2024/11/14 2:32:48

1.Apache Shiro

 

Apache Shiro Reference Documentation | Apache Shiro

Apache Shiro 是一个功能强大且易于使用的 Java 安全(权限)框架。Shiro 可以完
成:认证、授权、加密、会话管理、与 Web 集成、缓存 等。借助 Shiro 您可以快速轻松
地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序。

Shiro 是一个强大而灵活的开源安全框架,能够非常清晰的处理认证、授权、管理会话以及密码加密。如下是它所具有的特点:

· 易于理解的 Java Security API;

· 简单的身份认证(登录),支持多种数据源(LDAP,JDBC 等);

· 对角色的简单的签权(访问控制),也支持细粒度的鉴权;

· 支持一级缓存,以提升应用程序的性能;

· 内置的基于 POJO 企业会话管理,适用于 Web 以及非 Web 的环境;

· 异构客户端会话访问;

· 非常简单的加密 API;

· 不跟任何的框架或者容器捆绑,可以独立运行。

推荐shiro的参考手册介绍 - 《Apache Shiro 1.2.x 参考手册》 - 书栈网 · BookStack

 2.结构

  • Subject (org.apache.shiro.subject.Subject)

正在与软件交互的一个特定的实体“view”(用户、第三方服务、时钟守护任务等)。

  • SecurityManager (org.apache.shiro.mgt.SecurityManager)

如同上面提到的,SecurityManager 是 Shiro 的核心,它基本上就是一把“保护伞”用来协调它管理的组件使之平稳地一起工作,它也管理着 Shiro 中每一个程序用户的视图,所以它知道每个用户如何执行安全操作。

  • Authenticator(org.apache.shiro.authc.Authenticator)

Authenticator 是一个组件,负责执行和反馈用户的认证(登录),如果一个用户尝试登录,Authenticator 就开始执行。Authenticator 知道如何协调一个或多个保存有相关用户/帐号信息的 Realm,从这些 Realm中获取这些数据来验证用户的身份以确保用户确实是其表述的那个人。

  • Authentication Strategy(org.apache.shiro.authc.pam.AuthenticationStrategy)

如果配置了多个 Realm,AuthenticationStrategy 将会协调 Realm 确定在一个身份验证成功或失败的条件(例如,如果在一个方面验证成功了但其他失败了,这次尝试是成功的吗?是不是需要所有方面的验证都成功?还是只需要第一个?)

  • Authorizer(org.apache.shiro.authz.Authorizer)

Authorizer 是负责程序中用户访问控制的组件,它是最终判断一个用户是否允许做某件事的途径,像 Authenticator 一样,Authorizer 也知道如何通过协调多种后台数据源来访问角色和权限信息,Authorizer 利用这些信息来准确判断一个用户是否可以执行给定的动作。

  • SessionManager(org.apache.shiro.session.mgt.SessionManager)

SessionManager 知道如何创建并管理用户 Session 生命周期而在所有环境中为用户提供一个强有力的 Session 体验。这在安全框架领域是独一无二—Shiro 具备管理在任何环境下管理用户 Session 的能力,即使没有 Web/Servlet 或者 EJB 容器。默认情况下,Shiro 将使用现有的session(如Servlet Container),但如果环境中没有,比如在一个独立的程序或非 web 环境中,它将使用它自己建立的 session 提供相同的作用,sessionDAO 用来使用任何数据源使 session 持久化。

  • SessionDAO(org.apache.shiro.session.mgt.eis.SessionDAO)

SessionDAO 代表 SessionManager 执行 Session 持久(CRUD)动作,它允许任何存储的数据挂接到 session 管理基础上。

  • CacheManager(org.apache.shiro.cache.CacheManager)

CacheManager 为 Shiro 的其他组件提供创建缓存实例和管理缓存生命周期的功能。因为 Shiro 的认证、授权、会话管理支持多种数据源,所以访问数据源时,使用缓存来提高访问效率是上乘的选择。当下主流开源或企业级缓存框架都可以继承到 Shiro 中,来获取更快更高效的用户体验。

  • Cryptography (org.apache.shiro.crypto.*)

Cryptography 在安全框架中是一个自然的附加产物,Shiro 的 crypto 包包含了易用且易懂的加密方式,Hashes(即digests)和不同的编码实现。该包里所有的类都亦于理解和使用,曾经用过 Java 自身的加密支持的人都知道那是一个具有挑战性的工作,而 Shiro 的加密 API 简化了 java 复杂的工作方式,将加密变得易用。

  • Realms (org.apache.shiro.realm.Realm)

如同上面提到的,Realm 是 shiro 和你的应用程序安全数据之间的“桥”或“连接”,当实际要与安全相关的数据进行交互如用户执行身份认证(登录)和授权验证(访问控制)时,shiro 从程序配置的一个或多个Realm 中查找这些数据,你需要配置多少个 Realm 便可配置多少个 Realm(通常一个数据源一个),shiro 将会在认证和授权中协调它们。

2.依赖

         <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.3.2</version>
        </dependency>

3.认证案列

3-1利用配置进行登录

1.案列需要依赖.test文件夹全部删掉,我没有用spring的test依赖 ,启动代码会报错

<?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.5.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.example</groupId>
    <artifactId>shiro</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <!-- compiler插件, 设定JDK版本 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2.在 resources 新建一个shiro.ini文件 

#声明用户账号
[users]
jay=123

 3.编写测试代码

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;

/**
 * @Description:shiro的第一个例子
 */
public class HelloShiro {

    @Test
    public void shiroLogin() {
        //导入权限ini文件构建权限工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //工厂构建安全管理器
        SecurityManager securityManager = factory.getInstance();
        //使用SecurityUtils工具生效安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        //使用SecurityUtils工具获得主体
        Subject subject = SecurityUtils.getSubject();
        //构建账号token
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jay", "123");
        //登录操作
        subject.login(usernamePasswordToken);
        System.out.println("是否登录成功:" + subject.isAuthenticated());
    }
}

 4.运行结果

3-2模拟数据库的登录基于realm

1.新建service包

这里我只是为了模拟,所以不需要新导入依赖 还是3-1中的依赖 ,我们这里的service包只是为了模拟操作,不需要加什么注解 来交由spring来管理我们就是简单 测试 创建一个根据账号获取密码的接口就行了

 

package com.example.shiro.service;

/**
 * 模拟数据库操作服务接口
 */
public interface SecurityService {

    /**
     * @Description 查找密码按用户登录名
     * @param loginName 登录名称
     * @return  密码
     */
    String findPasswordByLoginName(String loginName);
}

package com.example.shiro.service.impi;


import com.example.shiro.service.SecurityService;

public class SecurityServiceImpl implements SecurityService {
    @Override
    public String findPasswordByLoginName(String loginName) {
        
        return "123";
    }
}

2.新建realm包

这个包主要存放我们权限一些类 ,在这个包新建 DefinitionRealm

package com.example.shiro.realm;

import com.example.shiro.service.SecurityService;
import com.example.shiro.service.impi.SecurityServiceImpl;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;



public class DefinitionRealm extends AuthorizingRealm {



    /**
     * @param authenticationToken 认证方法
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取登录名
        String loginName = (String) authenticationToken.getPrincipal();
        SecurityService securityService = new SecurityServiceImpl();
        final String password = securityService.findPasswordByLoginName(loginName);  //通过模拟的数据获取密码
        /**
         * 如果查询出来的密码是空的或者是null 就代表这个 账号不存在
         */
        if ("".equals(password) || password == null) {
            throw new UnknownAccountException("账户不存在");
        }
        //传递账号和密码
        return  new SimpleAuthenticationInfo(loginName,password,getName());
    }

    /**
     * @param principalCollection 鉴权方法
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}

3.修改shiro.ini文件

注意自己的包名

#声明自定义的realm,且为安全管理器指定realms
[main]
definitionRealm=com.example.shiro.realm.DefinitionRealm
securityManager.realms=$definitionRealm

4.运行结果

3-3 Realm使用散列算法(密码加密登录)

Shiro提供了base64和16进制字符串编码/解码的API支持,方便一些编码解码操作。

Shiro内部的一些数据的【存储/表示】,都使用了base64和16进制字符串

包结构如下 ,个别类不需要要  测试的密码还是写死的,只是模拟操作。

  

 1.建立一个生成加密的工具类

在tool包建一个

package com.example.shiro.tools;

import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;

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

/**
 * @Description 生成摘要
 */
public class DigestsUtil {


    public static final String SHA1 = "SHA-1";   //加密的算法
    public static final Integer ITERATIONS = 512;   //加密的次数

    /**
     * 散列盐加密
     *
     * @param input 输入参数
     * @param salt  盐
     * @return 加密的数据
     */
    public static String sha1(String input, String salt) {
        return new SimpleHash(SHA1, input, salt, ITERATIONS).toString();
    }

    /**
     * 随机生成salt
     *
     * @return hex编码的salt
     */

    public static String generateSalt() {
        final SecureRandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
        return randomNumberGenerator.nextBytes().toHex();
    }

    /**
     * @param passwordPlain 密文密码
     * @return map-> salt 和密文密码
     * @Description
     */
    public static Map<String, String> entryPassword(String passwordPlain) {
        Map<String, String> map = new HashMap<>();
        String salt = generateSalt();
        String password = sha1(passwordPlain, salt);
        map.put("salt", salt);
        map.put("password", password);
        return map;
    }

}

编码解密的工具类(可以不用) 

package com.example.shiro.tools;

import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.Hex;

/**
 * @Description:封装base64和16进制编码解码工具类
 */
public class EncodesUtil {

    /**
     * @Description HEX-byte[]--String转换
     * @param input 输入数组
     * @return String
     */
    public static String encodeHex(byte[] input){
        return Hex.encodeToString(input);
    }

    /**
     * @Description HEX-String--byte[]转换
     * @param input 输入字符串
     * @return byte数组
     */
    public static byte[] decodeHex(String input){
        return Hex.decode(input);
    }

    /**
     * @Description Base64-byte[]--String转换
     * @param input 输入数组
     * @return String
     */
    public static String encodeBase64(byte[] input){
        return Base64.encodeToString(input);
    }

    /**
     * @Description Base64-String--byte[]转换
     * @param input 输入字符串
     * @return byte数组
     */
    public static byte[] decodeBase64(String input){
        return Base64.decode(input);
    }

}

2.编写业务层代码(这里只是模拟操作,不是真正的service层)

接口

package com.example.shiro.service;

import java.util.Map;

/**
 * 模拟数据库操作服务接口
 */
public interface SecurityService {

    /**
     * @Description 查找密码按用户登录名
     * @param loginName 登录名称
     * @return  密码
     */
   Map<String,String> findPasswordByLoginName(String loginName);
}

实现接口

package com.example.shiro.service.impl;


import com.example.shiro.service.SecurityService;
import com.example.shiro.tools.DigestsUtil;

import java.util.Map;

public class SecurityServiceImpl implements SecurityService {
    @Override
    public Map<String, String> findPasswordByLoginName(String loginName) {
        return DigestsUtil.entryPassword("123");

    }
}

3. 在realm包下设置认证规则

package com.example.shiro.realm;

import com.example.shiro.service.SecurityService;

import com.example.shiro.service.impl.SecurityServiceImpl;
import com.example.shiro.tools.DigestsUtil;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.Map;


public class DefinitionRealm extends AuthorizingRealm {

    public DefinitionRealm(){
        //指定密码匹配方式为sha1
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(DigestsUtil.SHA1);
        //指定密码迭代次数
        matcher.setHashIterations(DigestsUtil.ITERATIONS);
        //使用父亲方法使匹配方式生效
        setCredentialsMatcher(matcher);

    }


    /**
     * @param authenticationToken 认证方法
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取登录名
        String loginName = (String) authenticationToken.getPrincipal();
        SecurityService securityService = new SecurityServiceImpl();
        final Map<String, String> map = securityService.findPasswordByLoginName(loginName);//通过模拟的数据获取密码
        if(map.isEmpty()){
            throw new UnknownAccountException("账号不存在");
        }
        final String salt = map.get("salt");
        final String password = map.get("password");
        return new SimpleAuthenticationInfo(loginName,password, ByteSource.Util.bytes(salt), getName());


    }

    /**
     * @param principalCollection 鉴权方法
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}

4.测试

别把3-2中的shiro.ini文件删了 还要用

package com.example.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;

/**
 * @Description:shiro的第一个例子
 */
public class HelloShiro {

    @Test
    public void shiroLogin() {
        //导入权限ini文件构建权限工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //工厂构建安全管理器
        SecurityManager securityManager = factory.getInstance();
        //使用SecurityUtils工具生效安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        //使用SecurityUtils工具获得主体
        Subject subject = SecurityUtils.getSubject();
        //构建账号token
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jay", "123");
        //登录操作
        subject.login(usernamePasswordToken);
        System.out.println("是否登录成功:" + subject.isAuthenticated());
    }
}

 5.运行结果

 4.认证+鉴权案列

简单就是不同的角色用户只能访问指定的信息 ,我们需要知道用户有那些角色,用户有那些权限  ,包结构和之前的一致3-3

1.新增两个查询角色和权限的接口,在SecurityService接口

 /**
     * @Description 查找角色按用户登录名
     * @param  loginName 登录名称
     * @return
     */
    List<String> findRoleByLoginName(String loginName);

    /**
     * @Description 查找资源按用户登录名
     * @param  loginName 登录名称
     * @return
     */
    List<String>  findPermissionByLoginName(String loginName);

 2.实现


    @Override
    public List<String> findRoleByLoginName(String loginName) {
        List<String> list = new ArrayList<>();
        list.add("admin");
        list.add("dev");
        return list;
    }

    @Override
    public List<String> findPermissionByLoginName(String loginName) {
        List<String> list = new ArrayList<>();
        list.add("order:add");
        list.add("order:list");
        list.add("order:del");
        return list;
    }

3.添加鉴权方法 

 /**
     * @param principals 鉴权方法
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //拿到用户认证凭证信息
        String loginName = (String)  principals.getPrimaryPrincipal();
        //从数据库中查询对应的角色和资源
        SecurityService securityService = new SecurityServiceImpl();
        List<String> roles = securityService.findRoleByLoginName(loginName);
        List<String> permissions = securityService.findPermissionByLoginName(loginName);
        //构建资源校验
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.addRoles(roles);
        authorizationInfo.addStringPermissions(permissions);
        return authorizationInfo;
    }

 4.测试

package com.example.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;

/**
 * @Description:shiro的第一个例子
 */
public class HelloShiro {

    @Test
    public void testPermissionRealm() {
        Subject subject = shiroLogin("jay", "123");
        //判断用户是否已经登录
        System.out.println("是否登录成功:" + subject.isAuthenticated());

        //---------检查当前用户的角色信息------------
        System.out.println("是否有管理员角色:"+subject.hasRole("admin"));
        //---------如果当前用户有此角色,无返回值。若没有此权限,则抛 UnauthorizedException------------
        try {
            subject.checkRole("coder");
            System.out.println("有coder角色");
        }catch (Exception e){
            System.out.println("没有coder角色");
        }

        //---------检查当前用户的权限信息------------
        System.out.println("是否有查看订单列表资源:"+subject.isPermitted("order:list"));
        //---------如果当前用户有此权限,无返回值。若没有此权限,则抛 UnauthorizedException------------
        try {
            subject.checkPermissions("order:add", "order:del");
            System.out.println("有添加和删除订单资源");
        }catch (Exception e){
            System.out.println("没有有添加和删除订单资源");
        }

    }


    /**
     * @Description 登录方法
     */
    private Subject shiroLogin(String loginName,String password) {
        //导入权限ini文件构建权限工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //工厂构建安全管理器
        SecurityManager securityManager = factory.getInstance();
        //使用SecurityUtils工具生效安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        //使用SecurityUtils工具获得主体
        Subject subject = SecurityUtils.getSubject();
        //构建账号token
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginName, password);
        //登录操作
        subject.login(usernamePasswordToken);
        return subject;
    }
}

5.运行结果 

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

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

相关文章

PHPExcel基本使用(2) 导入图片

一、效果二、代码一、效果 基于这篇 PHPExcel基本使用&#xff08;2&#xff09; 导入图片 调整 二、代码 基于thinkphp5.1 <?phpnamespace app\index\controller;use think\facade\Env;class Test {public function test(){self::excelAction();}/*** todo 导出报表*…

Microcontent - 微内容

这两年&#xff0c;微内容不断被人提及。微内容是什么&#xff1f;微内容解决什么问题&#xff1f;今天我们一起来看看这个话题。 作者&#xff1a;Sarah Cuellar - 1 - 什么是微内容 什么是微内容&#xff1f;微内容指的是小块的内容&#xff0c;它们遵循具体的的结构规则…

classnames 源码学习笔记与解读

前言 这里我引用源码文档中的一句话来作为开场白&#xff1a; A simple JavaScript utility for conditionally joining classNames together. 话不多说&#xff0c;咱们直接开始 classnames 的源码学习。 核心源码解读 直接来看它的源码部分&#xff0c;以下这是 classnam…

Win10的几个实用技巧系列之win10和win8系统哪个好用、系统任务栏和窗口假死的解决方法

目录 win10系统任务栏和窗口假死怎么办?win10系统任务栏和窗口假死的解决方法 win10系统任务栏和窗口假死怎么解决 Win10进不去Epic下载的死亡搁浅怎么办?Win10玩死亡搁浅闪退的解决方法 Epic领取的死亡搁浅进不去 Win10玩死亡搁浅闪退的解决方法 win10和win8系统哪个好用…

Eth09- EthCtrlConfig:以太网控制器写MAC地址到NVM中的配置

文章目录 1 MAC地址保存到非易失性存储器中传送门 ==>> AutoSAR入门和实战系列总目录 1 MAC地址保存到非易失性存储器中 如果想把MAC地址保存到非易失性存储器中,防止掉电之后MAC地址不存在了,可以通过以下的配置参数,实现实时保存MAC地址到NVM中 EthCtrlConfig/…

【Effective Objective - C】—— 读书笔记(四)

【Effective Objective - C】—— 读书笔记&#xff08;四&#xff09; 协议与分类 文章目录【Effective Objective - C】—— 读书笔记&#xff08;四&#xff09;协议与分类23.通过委托与数据源协议进行对象间通信要点&#xff1a;24.将类的实现代码分散到便于管理的数个分类…

Friedman 检验后的two-tailed Nemenyi test和the two-tailed Bonferroni-Dunn test的关键值

Critical values qαq_{\alpha}qα​ for post-hoc tests after the Friedman testCritical values qαq_{\alpha}qα​ for the two-tailed Nemenyi test Critical values qαq_{\alpha}qα​ for the two-tailed Bonferroni-Dunn test 其中classifiers是比较的方法个数&#…

【nowcoder】笔试强训Day15

目录 一、选择题 二、编程题 2.1 查找输入整数二进制中1的个数 2.2 手套 一、选择题 1.给出数据表 score(stu-id,name,math,english,Chinese), 下列语句正确的是&#xff08; &#xff09; A. Select sum(math),avg(chinese) from score B. Select *,sum(english) from …

初步改造2

1.找到登录按钮的触发方法 views/login/index.vue 找到是handleLogin 接着发现调用的是vuex里面的user/login方法 2.vuex中的方法&#xff0c;其实对应于"store/modules/user.js 中actions的login方法 3.前端请求与发现无响应&#xff0c;我们先用postman排除是后端问题&a…

Java集合 - HashMap

介绍 HashMap Map 是一种存储键值对的集合。Map 集合可以根据 key 快速查找对应的 value 值。HashMap 是 Map 类型的一中。 HashMap 的底层存储结构是&#xff1a;数组 链表 红黑树。 下面我们通过 HashMap 的新增操作、查找操作来看 HashMap 的底层存储结构。 HashMap 的…

深入理解ConcurrentHashMap1.8源码

1. 概述 之前介绍了ConcurrentHashMap1.7&#xff0c;采用的是数组分段锁的方式来实现的。虽然说采用分段锁的方式能够在一定程度上提高并发的效率&#xff0c;但是锁的粒度是Segment级别的&#xff0c;其实还是挺大的。 于是&#xff0c;ConcurrentHashMap1.8继续在1.7版本上…

postgresql_internals-14 学习笔记(五)Buffer Cache

新年的第一篇博客~ 一、 Buffer Cache简介 1. 主要用途 调和内存&#xff08;ns级&#xff09;与磁盘&#xff08;ms级&#xff09;间的速度差异。 pg不仅用自己的buffer cache&#xff0c;也用os cache&#xff0c;所以它使用了“双缓存”&#xff0c;这也是很多文档推荐sha…

《UEFI内核导读》UEFI是不是操作系统?

敬请关注微信公众号&#xff1a;“固件C字营” 最近一直在思考一个问题&#xff0c;UEFI是什么&#xff1f;UEFI算不算是操作系统&#xff1f; 众所周知&#xff0c;计算机系统是由软件和硬件两大部分组成的&#xff0c;但从更科学的角度来划分&#xff0c;我们其实可以分得更…

电子学会2020年9月青少年软件编程(图形化)等级考试试卷(四级)答案解析

目录 一、单选题&#xff08;共15题&#xff0c;每题2分&#xff0c;共30分&#xff09; 二、判断题&#xff08;共10题&#xff0c;每题2分&#xff0c;共20分&#xff09; 三、编程题【该题由测评师线下评分】&#xff08;共5题&#xff0c;共50分&#xff09; 青少年软件…

【MySQL】说透锁机制(三)行锁升表锁如何避免? 锁表了如何排查?

文章目录前言哪些场景会造成行锁升表锁&#xff1f;如何避免?如何分析排查?查看InnoDB_row_lock%相关变量查看 INFORMATION_SCHEMA系统库总结最后前言 在上文我们曾小小的提到过&#xff0c;在索引失效的情况下&#xff0c;MySQL会把所有聚集索引记录和间隙都锁上&#xff0…

【正点原子】嵌入式Linux C应用编程-第十一章

第十一章&#xff1a;线程 前言&#xff1a; 与进程类似&#xff0c;线程是允许应用程序并发执行多个任务的一种机制&#xff0c;线程参与系统调度&#xff0c;事实上&#xff0c;系统调度的最小单元为线程&#xff0c;而不是进程 1&#xff1a;线程的概念 什么是线程&#xff…

【游戏编程扯淡精粹】自研引擎切 UE

【游戏编程扯淡精粹】自研引擎切 UE UF2022 的两篇讲座&#xff0c;再加上 The Machinery 引擎项目失败 结合过去两年笔者使用自研引擎的体验&#xff0c;其实有一部分是共通的 Crystal Dynamics&#xff1a;如何从自研引擎转变到虚幻引擎5 游戏技术&#xff08;featurelist…

LVGL的学习及使用

1、LVGL简介 LVGL是最受欢迎的免费开源嵌入式图形库&#xff0c;可为任何MCU、MPU和显示器类型创建漂亮的用户界面。使用SquareLine工作室&#xff0c;使用拖放UI编辑器来简化开发。 1.1、LVGL源码下载 lvgl 在github 上的开源代码 https://github.com/lvgl/lvgl 下载的源码包里…

Vue的数据绑定

一、Vue的数据绑定 1、单向数据绑定&#xff1a;将Model绑定到View上&#xff0c;当通过JavaScript代码改变了Model时&#xff0c;View就会自动刷新。不需要进行额外的DOM 操作就可以实现视图和模型的联动 ​ a、数据只保存一份 ​ b、data—->DOM ​ &#xff08;1&am…

在wsl下开发T113的主线linux(3)-写入spinand测试

接下来是烧写入硬件验证&#xff0c;我的板子焊接的是W25N01GV&#xff0c;这里使用xfel&#xff0c;因为支持写入spi-nand。GitHub - xboot/xfel: Tiny FEL tools for allwinner SOC, support RISC-V D1 chipTiny FEL tools for allwinner SOC, support RISC-V D1 chip - GitH…