【Shiro】SpringBoot集成Shiro权限认证《下》

news2024/11/25 1:04:18

本章节是在上一节的基础上继续完成,如有不明白,请看上一篇文章【Shiro】SpringBoot集成Shiro权限认证《上》。

SQL语句

这里我们需要先准备好SQL语句,如下所示:

/*
Navicat MySQL Data Transfer

Source Server         : local
Source Server Version : 50525
Source Host           : localhost:3306
Source Database       : new-shiro

Target Server Type    : MYSQL
Target Server Version : 50525
File Encoding         : 65001

Date: 2023-09-27 12:39:49
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for sys_permissions
-- ----------------------------
DROP TABLE IF EXISTS `sys_permissions`;
CREATE TABLE `sys_permissions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `code` varchar(20) NOT NULL COMMENT '权限名称',
  `name` varchar(20) NOT NULL COMMENT '权限标识',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

-- ----------------------------
-- Records of sys_permissions
-- ----------------------------
INSERT INTO `sys_permissions` VALUES ('5', 'user:update', '用户修改');
INSERT INTO `sys_permissions` VALUES ('6', 'user:delete', '用户删除');

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `code` varchar(50) DEFAULT NULL COMMENT '角色编码',
  `name` varchar(50) NOT NULL COMMENT '角色名称',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', 'admin', '管理员');
INSERT INTO `sys_role` VALUES ('20', 'user', '普通用户');

-- ----------------------------
-- Table structure for sys_roles_permissions
-- ----------------------------
DROP TABLE IF EXISTS `sys_roles_permissions`;
CREATE TABLE `sys_roles_permissions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_id` int(11) NOT NULL COMMENT '角色编号',
  `permission_id` int(11) NOT NULL COMMENT '权限编号',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `role_id` (`role_id`) USING BTREE,
  KEY `permission_id` (`permission_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='角色权限表';

-- ----------------------------
-- Records of sys_roles_permissions
-- ----------------------------
INSERT INTO `sys_roles_permissions` VALUES ('2', '20', '5');
INSERT INTO `sys_roles_permissions` VALUES ('5', '1', '5');
INSERT INTO `sys_roles_permissions` VALUES ('6', '1', '6');
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username` varchar(30) NOT NULL COMMENT '登录名',
  `password` varchar(255) NOT NULL COMMENT '用户密码',
  `name` varchar(30) DEFAULT NULL COMMENT '昵称',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `un_username_easyuser` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用户表';

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'admin', '123456', '小王');
INSERT INTO `sys_user` VALUES ('18', 'halo', '123456', 'Halo');

-- ----------------------------
-- Table structure for sys_users_roles
-- ----------------------------
DROP TABLE IF EXISTS `sys_users_roles`;
CREATE TABLE `sys_users_roles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '用户编号',
  `role_id` int(11) NOT NULL COMMENT '角色编号',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `user_id` (`user_id`) USING BTREE,
  KEY `role_id` (`role_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='用户角色表';

-- ----------------------------
-- Records of sys_users_roles
-- ----------------------------
INSERT INTO `sys_users_roles` VALUES ('1', '1', '1');
INSERT INTO `sys_users_roles` VALUES ('12', '18', '20');


依赖引入


      <properties>
        <java.version>8</java.version>
        <mybatis-plus.version>3.1.1</mybatis-plus.version>
        <mysql.version>5.1.47</mysql.version>
        <alibaba.durid.version>1.0.9</alibaba.durid.version>
      </properties>
        <!--Mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!--阿里巴巴连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${alibaba.durid.version}</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

代码生成

这里我们可以使用IDEA插件《EasyCode》生成Mybatis-Plus模板的后端代码。

生成的结果如下所示:

在这里插入图片描述

统一返回结果

这块是为了返回统一的结果,下面会用到。

Result.java

新建文件夹 common

@Data
public class Result<T> implements Serializable {

    private String code;
    private String message;
    private T data;

    public Result(String code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public Result(ResultCodeEnum resultCodeEnum, T data) {
        this.code = resultCodeEnum.getCode();
        this.message = resultCodeEnum.getMessage();
        this.data = data;
    }

    public static <T> Result<T> success(T data) {
        return new Result<T>(ResultCodeEnum.SUCCESS, data);
    }

    public static Result fail(ResultCodeEnum resultCodeEnum) {
        return new Result(resultCodeEnum, "");
    }

}

ResultCodeEnum.java

新建文件夹 enums


public enum ResultCodeEnum {
    SUCCESS("0000", "操作成功"),
    SUCCESS_QUERY("0001", "查询成功"),
    SUCCESS_ADD("0002", "添加成功"),
    SUCCESS_UPDATE("0003", "更新成功"),
    SUCCESS_DELETE("0004", "删除成功"),


    TOKEN_ERROR("1000", "token错误"),
    TOKEN_NULL("1001", "token为空"),
    TOKEN_EXPIRED("1002", "token过期"),
    TOKEN_INVALID("1003", "token无效"),

    USER_ERROR("2000", "用户名密码错误"),
    USER_NOT_EXISTS("2001", "用户不存在"),
    USER_INVALID("2002", "用户无效"),
    USER_EXPIRED("2003", "用户过期"),
    USER_BLOCKED("2004", "用户封禁"),
    USER_PASSWORD_ERROR("2005", "密码错误"),

    PARAM_ERROR("3000", "参数错误"),
    PARAM_NULL("3001", "参数为空"),
    PARAM_FORMAT_ERROR("3002", "参数格式不正确"),
    PARAM_VALUE_INCORRECT("3003", "参数值不正确"),
    PARAM_DUPLICATE("3004", "参数重复"),
    PARAM_CONVERT_ERROR("3005", "参数转化错误"),

    AUTHORITY_ERROR("4000", "权限错误"),
    AUTHORITY_UNAUTHORIZED("4001", "无权限"),

    SERVER_ERROR("5000", "服务器内部错误"),
    SERVER_UNAVAILABLE("5001", "服务器不可用"),


    ;

    ResultCodeEnum(String code, String message) {
        this.code = code;
        this.message = message;
    }

    private String code;
    private String message;

    public String getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

认证逻辑及授权

数据库操作逻辑

在SysUserService 新增 查询用户信息方法及查询角色、权限信息方法。

如下所示:

SysUserService.java

public interface SysUserService extends IService<SysUser> {

    /**
     * 根据用户名查询用户信息
     * @param userName
     * @return
     */
    SysUser queryUserInfoByUserName(String userName);

    /**
     * 根据用户ID查询用户角色、权限相关信息
     * @param userName
     * @return
     */
    SysUser queryUserInfoByUserInfo(String userName);
}

SysUserServiceImpl.java

@Service("sysUserService")
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Resource
    SysRoleMapper sysRoleMapper;

    @Resource
    SysPermissionsMapper sysPermissionsMapper;

    @Override
    public SysUser queryUserInfoByUserName(String userName) {
        return this.baseMapper.selectOne(new QueryWrapper<SysUser>().eq("username",userName));
    }

    @Override
    public SysUser queryUserInfoByUserInfo(String userName) {
        SysUser sysUser = this.baseMapper.selectOne(new QueryWrapper<SysUser>().eq("username",userName));
        List<SysRole> roleList = sysRoleMapper.querySysRoleByUserId(sysUser.getId());
        Set<SysPermissions> sysPermissionsSet = new HashSet<>();
        roleList.forEach(role->{
            sysPermissionsSet.addAll(this.sysPermissionsMapper.queryPermissionByRoleId(role.getId()));
        });
        sysUser.setSysRoleList(roleList);
        sysUser.setPermissionsSet(sysPermissionsSet);
        return sysUser;
    }
}

SysRoleMapper.java

public interface SysRoleMapper extends BaseMapper<SysRole> {

    /**
     * 根据用户ID查询角色信息
     * @param id
     * @return
     */
    @Select(" select t1.* from sys_role t1 inner join sys_users_roles t2 on t1.id = t2.role_id where t2.user_id = #{id} ")
    List<SysRole> querySysRoleByUserId(Integer id);
}

SysPermissionsMapper.java

/**
 * (SysPermissions)表数据库访问层
 *
 * @author halo-king
 * @since 2023-09-27 12:42:43
 */
public interface SysPermissionsMapper extends BaseMapper<SysPermissions> {
    /**
     * 根据角色ID查询角色信息
     * @param roleId
     * @return
     */
    @Select(" select t1.* from sys_permissions t1 inner join sys_roles_permissions t2 on t1.id = t2.permission_id where t2.role_id =#{roleId}")
    List<SysPermissions> queryPermissionByRoleId(Integer roleId);
}

在完成了数据库相关的操作逻辑后,我们需要修改 CustomerRealm 中的认证和授权逻辑。

认证

/**
     * 认证逻辑
     * @param authenticationToken
     * @return
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        System.out.println("执行了=>认证逻辑AuthenticationToken");
        if(authenticationToken.getPrincipal()==null){
            return null;
        }
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        SysUser sysUser = this.sysUserService.queryUserInfoByUserName(token.getUsername());

        if(sysUser == null){
            return null;
        }
        return  new SimpleAuthenticationInfo(sysUser.getUsername(), sysUser.getPassword(), getName());
    }

授权

 /**
     * 授权逻辑
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权逻辑PrincipalCollection");
        //获取登录用户名
        String userName = (String) principalCollection.getPrimaryPrincipal();
        SysUser sysUser = this.sysUserService.queryUserInfoByUserInfo(userName);

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        for (SysRole role : sysUser.getSysRoleList()) {
            //添加角色
            authorizationInfo.addRole(role.getCode());
            //添加权限
            for (SysPermissions permissions : sysUser.getPermissionsSet()) {
                authorizationInfo.addStringPermission(permissions.getCode());
            }
        }
        return authorizationInfo;
    }

统一接口返回

原来的登录接口

@GetMapping("/login")
    public String login(String userName,String passWord) {
        if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(passWord)) {
            return "用户名密码不能为空";
        }
        //用户认证信息
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userName, passWord);
        try {
            subject.login(usernamePasswordToken);
        } catch (UnknownAccountException e) {
            return "用户不存在";
        } catch (AuthenticationException e) {
            return "用户名密码错误";
        } catch (AuthorizationException e) {
            return "无权限登录";
        }
        return "登录成功";
    }

修改完后的登录接口

  @GetMapping("/login")
    public Result login(String userName, String passWord) {
        if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(passWord)) {
            return Result.fail(ResultCodeEnum.USER_OR_PWD_NOT_EMPTY);
        }
        //用户认证信息
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userName, passWord);
        try {
            subject.login(usernamePasswordToken);
        } catch (UnknownAccountException e) {
            return Result.fail(ResultCodeEnum.USER_NOT_EXISTS);
        } catch (AuthenticationException e) {
            return Result.fail(ResultCodeEnum.USER_ERROR);
        } catch (AuthorizationException e) {
            return Result.fail(ResultCodeEnum.AUTHORITY_UNAUTHORIZED);
        }
        return Result.success("登录成功");
    }

测试

登录测试

到这一步,我们就已经完成了登录和授权的操作,现在启动项目,测试。

不输入用户名和密码

访问地址:

    http://localhost:8082/login

返回结果:

{"code":"2006","message":"用户名或密码不能为空","data":""}

输入不存在的用户名和密码

访问地址:

http://localhost:8082/login?userName=test&passWord=123456

返回结果:

{"code":"2001","message":"用户不存在","data":""}

输入错误的用户名和密码

访问地址:

http://localhost:8082/login?userName=admin&passWord=12333

返回结果:

{"code":"2000","message":"用户名密码错误","data":""}

输入正确的用户名和密码

访问地址:

http://localhost:8082/login?userName=admin&passWord=123456

返回结果:

{"code":"0000","message":"操作成功","data":"登录成功"}

权限测试

注意:权限测试前提,需要先登录才行!!!

权限测试,我们分为方法授权和注解授权。
这里会列举一些小栗子,供大家参考。

通过上面的SQL,我们查询出用户admin 他具有角色为 admin 以及权限 user:update、user:delete.

方法授权

下面的代码,你可以方法放在LoginController 或者自己新建一个TestController 里面进行测试,都可。

@GetMapping("delete")
public Result delete() {
    Subject subject = SecurityUtils.getSubject();
    if(subject.isPermitted("user:delete")){
        return Result.success("delete success");
    }else{
        return Result.fail(ResultCodeEnum.AUTHORITY_UNAUTHORIZED);
    }
 }

访问地址:

http://localhost:8082/delete

返回结果:

{"code":"0000","message":"操作成功","data":"delete success"}

注解授权

当前用户拥有update,delete 但是没有 add 权限。

常规用的注解:

  • @RequiresAuthentication 需要完成用户登录
  • @RequiresGuest 未登录用户可以访问,登录用户不能访问
  • @RequiresPermissions 需要有对应资源权限
  • @RequiresRoles 需要有对应角色才能访问
  • @RequiresUser 需要用户完成登录并且实现了记住我功能
    @RequiresPermissions("user:update")
    @GetMapping("update")
    public Result<String> update() {
        return Result.success("update success ");
    }


    @RequiresPermissions("user:add")
    @GetMapping("add")
    public Result<String> add() {
        return Result.success("add success ");
    }

有权限

访问地址:

http://localhost:8082/update

返回结果:

{"code":"0000","message":"操作成功","data":"update success"}

无权限

访问地址:

http://localhost:8082/add

返回结果:

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Wed Sep 27 15:38:37 CST 2023
There was an unexpected error (type=Internal Server Error, status=500).
Subject does not have permission [user:add]

全局异常捕获

在上面的页面上,我们会发现,当出现没权有权限的时候,这样提示给用不是非常的不友好,所以,这里使用全局的异常捕获,给用户一个比较友好的体验。

新建一个exception文件夹,然后再文件加下新建 GlobalException.java

@Slf4j
@ControllerAdvice
public class GlobalException {

    @ExceptionHandler(AuthorizationException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public Result ExceptionHandler(AuthorizationException e) {
        // 打印堆栈,以供调试
        e.printStackTrace();
        return Result.fail(ResultCodeEnum.AUTHORITY_UNAUTHORIZED);
    }
    
    @ExceptionHandler(Exception.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result ExceptionHandler(Exception e) {
        // 打印堆栈,以供调试
        e.printStackTrace();
        return Result.fail(ResultCodeEnum.SERVER_ERROR);
    }

}

当我们再次测试上面的没有权限的接口时,返回的结果就是如下所示:

{"code":"4001","message":"无权限","data":""}

密码加密

密码加密

使用以下的代码,在新增用户的时候,生成密码

     System.out.println(new Md5Hash("123456", "YX"));

修改ShiroConfig

  /**
     * Shiro自带密码管理器
     *
     * @return HashedCredentialsMatcher
     */
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        //Shiro自带加密
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //散列算法使用md5
        credentialsMatcher.setHashAlgorithmName("md5");
        //散列次数,2表示md5加密两次
        credentialsMatcher.setHashIterations(1);
        return credentialsMatcher;
    }

修改自定义Realm,即:密码验证那块逻辑。


/**
 * 认证逻辑
 * @param authenticationToken
 * @return
 */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        System.out.println("执行了=>认证逻辑AuthenticationToken");
        if(authenticationToken.getPrincipal()==null){
            return null;
        }
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        SysUser sysUser = this.sysUserService.queryUserInfoByUserName(token.getUsername());

        if(sysUser == null){
            return null;
        }
        SimpleAuthenticationInfo  simpleAuthenticationInfo  = new SimpleAuthenticationInfo(sysUser.getUsername(), sysUser.getPassword(), getName());
        simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("YX")); //加盐
        return  simpleAuthenticationInfo;
}

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

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

相关文章

美丽的图论

**美丽的图论 ** Prf &#x1f609; 对于 n 个顶点上的树的数量 n^(n-2)&#xff0c;这是凯莱公式&#xff0c;用于计算 n 个顶点上的树的数量&#xff0c;被放置在一个由 4 个标记顶点组成的圆圈中。 使用 Figma 制作 在图论中&#xff0c;树只是一个没有环的图。 树在离散…

Python机器学习-灵敏度分析

文章目录 灵敏度分析详细步骤单参数分析 灵敏度分析详细步骤 灵敏度分析是一种用于确定输入参数变化对模型输出结果的影响程度的方法。以下是进行灵敏度分析的一般步骤&#xff1a; 确定模型&#xff1a;选择需要进行灵敏度分析的模型&#xff0c;该模型必须具有可变参数和可…

算法框架-LLM-1-Prompt设计(一)

原文&#xff1a;算法框架-LLM-1-Prompt设计&#xff08;一&#xff09; - 知乎 目录 收起 1 prompt-engineering-for-developers 1.1 Prompt Engineering 1.1.1 提示原则 1. openai的环境 2. 两个基本原则 3. 示例 eg.1 eg.2 结构化输出 eg.3 模型检验 eg.4 提供示…

OpenCV实现视频的读取、显示、保存

目录 1&#xff0c;从文件中读取视频并播放 1.2代码实现 1.3效果展示 2&#xff0c;保存视频 2.1 代码实现 2.2 结果展示 1&#xff0c;从文件中读取视频并播放 在OpenCV中我们需要获取一个视频&#xff0c;需要创建一个VideoCapture对象,指定你要读取的视频文件&am…

八大排序(三)堆排序,计数排序,归并排序

一、堆排序 什么是堆排序&#xff1a;堆排序&#xff08;Heap Sort&#xff09;就是对直接选择排序的一种改进。此话怎讲呢&#xff1f;直接选择排序在待排序的n个数中进行n-1次比较选出最大或者最小的&#xff0c;但是在选出最大或者最小的数后&#xff0c;并没有对原来的序列…

聊聊并发编程——线程池

目录 Java线程池 处理流程 线程池主要参数 常见的拒绝策略 execute和submit区别 关闭线程池 常见的线程池 newSingleThreadExecutor newFixedThreadPool newCachedThreadPool newScheduledThreadPool 线程池的状态 Java线程池 运用场景最多的并发框架&#xff0c;…

【面试总结大纲】

面试 springSpring AOP的具体实现核心概念分别指的是什么?基于注解的切面实现主要包括以下几个步骤&#xff1a;两个切面&#xff0c;它们之间的顺序是怎么控制的 springmvc的工作流程设计模式原则Spring 框架中用到了哪些设计模式&#xff1f; spring Spring AOP的具体实现 …

讲讲项目里的仪表盘编辑器(三)布局组件

布局容器处理 看完前面两章的讲解&#xff0c;我们对仪表盘系统有了一个大概的理解。接着我们讲讲更深入的应用。 上文讲解的编辑器只是局限于平铺的组件集。而在编辑器中&#xff0c;还会有一种组件是布局容器。它允许其他组件拖拽进入在里面形成自己的一套布局。典型的有分页…

如何实现电脑语音输入功能?

现在的手机都具备语音输入功能&#xff0c;并且识别率非常高&#xff0c;语音输入是目前最快速的文字输入方式&#xff0c;但是电脑上却无语音输入的功能&#xff0c;那么如何实现在电脑端也可进行语音输入的梦想呢&#xff1f;现在介绍一款小工具“书剑电脑语音输入法”&#…

Llama2-Chinese项目:4-量化模型

一.量化模型调用方式   下面是一个调用FlagAlpha/Llama2-Chinese-13b-Chat[1]的4bit压缩版本FlagAlpha/Llama2-Chinese-13b-Chat-4bit[2]的例子&#xff1a; from transformers import AutoTokenizer from auto_gptq import AutoGPTQForCausalLM model AutoGPTQForCausalLM…

DDD项目落地之充血模型实践

一、背景 充血模型是DDD分层架构中实体设计的一种方案&#xff0c;可以使关注点聚焦于业务实现&#xff0c;可有效提升开发效率、提升可维护性&#xff1b; 二、DDD项目落地整体调用关系 调用关系图中的Entity为实体&#xff0c;从进入领域服务&#xff08;Domin&#xff09;…

基于Java的健身房会员管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

【算法挨揍日记】day10——704. 二分查找、34. 在排序数组中查找元素的第一个和最后一个位置

704. 二分查找 704. 二分查找 题目描述&#xff1a; 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 解题思路&…

使用序列到序列深度学习方法自动睡眠阶段评分

深度学习方法&#xff0c;用于使用单通道脑电图进行自动睡眠阶段评分。 def build_firstPart_model(input_var,keep_prob_0.5):# List to store the output of each CNNsoutput_conns []######### CNNs with small filter size at the first layer ########## Convolutionnetw…

Ant-Design-Vue:a-range-picker组件国际化配置

在使用Ant-Design-Vue中的时间范围选择器开发个人项目时&#xff0c;发现默认显示为英文。如何解决呢&#xff1f; date-picker分类 Antd-Vue提供了DatePicker、MonthPicker、RangePicker、WeekPicker 几种类型的时间选择器&#xff0c;分别用于选择日期、月份、日期范围、周范…

JSON的MIME媒体类型是application/json

JSON&#xff08;全称 JavaScript Object Notation&#xff09;即JavaScript对象表示法&#xff0c;通知使用application/json媒体类型。 目录 1、JSON介绍 2、JSON语法 3、实践总结 运行环境&#xff1a; Windows-7-Ultimate-x64、Windows-10-BusinessEditions-21h2-x64 1…

最新AI智能问答系统源码/AI绘画系统源码/支持GPT联网提问/Prompt应用+支持国内AI提问模型

一、AI创作系统 SparkAi创作系统是基于国外很火的ChatGPT进行开发的AI智能问答系统和AI绘画系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图…

总部位于德国的拉丁美洲在线杂货配送服务商Jokr完成5000万美元D轮融资

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于德国柏林的拉丁美洲在线杂货配送服务提供商Jokr今日宣布已完成5000万美元D轮融资。 本轮融资完后Jokr的估值已达到8亿美金&#xff0c;本轮融资由convialit Ventures领投&#xff0c;Lomba…

XDM,10.1

XDM&#xff0c;今天是国庆&#xff0c;就没有其他啥事情&#xff0c;祝大家国庆节快乐&#xff0c;玩的开心。 这两天放假也有时间捣鼓自己的事情了&#xff0c;挺开心的&#xff0c;第一件事就是把自己的一个小开发板修好了&#xff0c;然后自己的小os也能跑了几个假的线程。…

基于Javaweb的护肤品推荐系统 /基于ssm的护肤品销售系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&a…