瑞吉外卖 - 后台系统登陆功能(3)

news2025/1/20 10:56:15

某马瑞吉外卖单体架构项目完整开发文档,基于 Spring Boot 2.7.11 + JDK 11。预计 5 月 20 日前更新完成,有需要的胖友记得一键三连,关注主页 “瑞吉外卖” 专栏获取最新文章。
相关资料:https://pan.baidu.com/s/1rO1Vytcp67mcw-PDe_7uIg?pwd=x548
提取码:x548

文章目录

    • 1.需求分析
    • 2.代码开发
      • 2.1 创建实体类
      • 2.2 创建基本项目结构
      • 2.3 编写 Mapper 接口
      • 2.4 Service 层
      • 2.5 Controller 层
    • 3.功能测试
    • 4.分析后台系统首页构成

1.需求分析

产品原型如下:

交互说明:

  1. 使用用户名和密码登录(用户名、密码不能为空),若为空提示“不能为空”;
  2. 成功登陆,进入系统;
  3. 登陆失败,提示语 3 秒“输入有误请重试,还剩 4 次!”;
  4. 限制输入 1-20 个字符。

项目中对应的页面路径:static/backend/page/login/login.html

由于上一篇文章中,我们已经设置了静态资源路径的映射,因此我们可以直接访问具体的登陆页面。启动程序,浏览器访问 http://localhost:8080/static/backend/page/login/login.html:

上面的 admin 用户我们在导数数据表的时候,在 employee 表中已经默认注册了一个员工:

其中的用户就是 admin,密码是经过加密后的字符串。我们可以通过浏览器打开调试工具(F12),查看点击登陆后的一些基本请求和响应信息:

可以发现,当我们点击登陆按钮时,页面会发送一个 POST 请求,请求路径为 “http://localhost:8080/employee/login” ,并且以 JSON 格式提交了请求参数 username 和 password,其中的 123456 就是数据库表中的密码解密后的明文形式。

该请求返回的状态码为 404,因为我们还没有在服务端处理此请求,所以我们需要做的第一件事就是创建相关的 controller 类来处理该请求,并按预期的方式进行响应。

下面我们通过 static/backend/page/login/login.html 源码进行进一步的分析,关键部分源码如下:

简单分析一下,首先我们发送了一个请求,点进 loginApi() 方法,涉及到的源码如下:

function loginApi(data) {
  // 通过axios发送请求
  return $axios({
    // 请求地址
    url: "/employee/login",
    // 请求方式
    method: "post",
    // 请求参数
    data,
  });
}

可以看到当我们点击登录按钮后,会通过 axios 发送一个 POST 请求,请求的路径便是 “/employee/login”。接着看上面截图圈出的其他部分知道,需要从响应对象中获取到几个基本信息:

  • code 用于表示是否登陆成功,约定 1 为登陆成功;
  • data 为用户信息;
  • 登陆成功后应该跳转到首页 “/backend/index.html”;
  • 登陆失败则返回失败信息 msg。

OK,基于上述需求分析,我们就可以正式进行功能的实现了。

2.代码开发

2.1 创建实体类

首先第一步肯定就是创建一个实体类 Employee 用于和数据表 employee 进行 ORM 映射。

在下载的资料的 “瑞吉外卖\瑞吉外卖项目\资料\实体类”目录下已经准备好了需要用到的各个实体类。我们首先在项目中创建一个 entity 包用于存放项目所需的实体类,然后将资料中的实体类一次性全部复制进去即可。

Employee 实体类完整代码如下:

package cn.javgo.reggie_take_out.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;

@Data
public class Employee implements Serializable {

    // 用于序列化的版本号
    private static final long serialVersionUID = 1L;
    // 自增主键
    private Long id;
    // 用户名
    private String username;
    // 姓名
    private String name;
    // 密码
    private String password;
    // 手机号
    private String phone;
    // 性别
    private String sex;
    // 身份证号
    private String idNumber;
    // 状态,0:禁用,1:启用
    private Integer status;
    // 创建时间
    private LocalDateTime createTime;
    // 更新时间
    private LocalDateTime updateTime;
    // 创建人
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    // 更新人
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
}

2.2 创建基本项目结构

再开始编写代码前,我们需要先创建好对应的包:

  • controller:控制层
  • mapper:持久层(这里有与使用 MyBatis Plus,故而将 dao 换成了 mapper)
  • service:业务逻辑层

最终的项目结构应该如下:

2.3 编写 Mapper 接口

使用了 MyBatis Plus 之后只需要将 Mapper 接口继承 MyBatis Plus 提供的 BaseMapper<T> 接口即可。

下面是 EmployeeMapper 接口完整代码:

package cn.javgo.reggie_take_out.mapper;

import cn.javgo.reggie_take_out.entity.Employee;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface EmployeeMapper extends BaseMapper<Employee>{

}

2.4 Service 层

同样,MyBatis Plus 提供了一个 IService<T> 接口,我们可以直接将 EmployeeService 接口继承它即可。

下面是 EmployeeService 接口完整代码:

package cn.javgo.reggie_take_out.service;

import cn.javgo.reggie_take_out.entity.Employee;
import com.baomidou.mybatisplus.extension.service.IService;

public interface EmployeeService extends IService<Employee> {

}

对应的我们需要准备一个实现类,MyBatis Plus 同样提供了一个IService<T> 接口的实现 ServiceImpl<M extends BaseMapper<T>, T>,因此直接用 EmployeeServiceImpl 实现类继承该实现类即可。

下面是 EmployeeServiceImpl 实现类完整代码:

package cn.javgo.reggie_take_out.service.impl;

import cn.javgo.reggie_take_out.entity.Employee;
import cn.javgo.reggie_take_out.mapper.EmployeeMapper;
import cn.javgo.reggie_take_out.service.EmployeeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {

}

2.5 Controller 层

在正式开始之前,我们需要准备一个返回结果类 R<T>,该类是一个通用类,服务端响应的所有结果最终都会包装成此类型返回给前端。

该类同样已经提供有,我们直接将其复制到项目的 cn.javgo.reggie_take_out.common 包下即可,其中的 common 包需要自行创建,用于存放各种通用类。

文件路径:瑞吉外卖\瑞吉外卖项目\资料\服务端返回结果类\R.java

该结果类完整代码如下:

package cn.javgo.reggie_take_out.common;

import lombok.Data;
import java.util.HashMap;
import java.util.Map;

/**
 * 通用返回结果类,服务端响应的数据最终都会封装成该类的对象
 */
@Data
public class R<T> {
    // 编码:1成功,0和其它数字为失败
    private Integer code;
    // 错误信息
    private String msg;
    // 数据
    private T data;
    // 动态数据
    private Map<String,Object> map = new HashMap<>();

    /**
     * 响应成功时调用,用于将数据封装到响应对象中,并返回状态码为1表示成功
     * @param object 响应数据
     * @return 响应对象
     * @param <T> 响应数据类型
     */
    public static <T> R<T> success(T object) {
        R<T> r = new R<>();
        r.data = object;
        r.code = 1;
        return r;
    }

    /**
     * 响应失败时调用,用于将错误信息封装到响应对象中,并返回状态码为0表示失败
     * @param msg 错误信息
     * @return  响应对象
     * @param <T> 响应数据类型
     */
    public static <T> R<T> error(String msg) {
        R<T> r = new R<>();
        r.msg = msg;
        r.code = 0;
        return r;
    }

    /**
     * 用于向响应对象中添加动态数据
     * @param key 键
     * @param value 值
     * @return 响应对象
     */
    public R<T> add(String key, Object value) {
        this.map.put(key, value);
        return this;
    }
}

下面开始正式编写控制层的相关代码,我们准备一个 EmployeeController 类在其中编写登陆方法。登陆方法的处理逻辑大致如下:

  1. 将页面提交的密码 password 进行 md5 加密处理;
  2. 根据页面提交的用户名 username 查询数据库;
  3. 如果没有查询到,则返回登陆失败结果;
  4. 进行密码比对,如果不一致则返回登陆失败结果;
  5. 查看员工状态,如果为已禁用状态,则返回员工已禁用结果;
  6. 登陆成功,将员工 id 存入 Session 并返回登陆成功的结果。

流程图如下:

EmployeeController 类的登陆部分代码如下:

package cn.javgo.reggie_take_out.controller;

import cn.javgo.reggie_take_out.common.R;
import cn.javgo.reggie_take_out.entity.Employee;
import cn.javgo.reggie_take_out.service.EmployeeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.DigestUtils;
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 javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
    @Resource
    private EmployeeService employeeService;

    /**
     * 处理登陆请求
     * 说明:
     * 1.由于前端携带的用户名和密码是以 JSON 形式提交的,所以需要使用 @RequestBody 注解将请求体中的 JSON 数据转换为 Employee 对象
     * 2.由于前端传过来的是明文密码,所以需要对密码进行 MD5 加密处理
     * 3.需要使用 HttpServletRequest 对象获取 session 对象,用于将登陆成功的用户信息存入 session 中,以便后续的请求可以直接获取到用户信息
     *
     * @param request  请求对象
     * @param employee 员工对象
     * @return 响应对象
     */
    @PostMapping("/login")
    public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee) {
        // 1.将页面提交的密码进行 MD5 加密处理
        String password = employee.getPassword();
        password = DigestUtils.md5DigestAsHex(password.getBytes());

        // 2.根据用户名查询数据库
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Employee::getUsername, employee.getUsername());
        Employee emp = employeeService.getOne(queryWrapper);

        // 3.如果没有查询到则返回登录失败结果
        if (emp == null) {
            return R.error("登陆失败");
        }

        // 4.进行密码比对,如果不一致则返回登录失败结果
        if (!emp.getPassword().equals(password)) {
            return R.error("登陆失败");
        }

        // 5.查看员工状态,如果为已禁用状态,则返回员工已禁用结果
        if (emp.getStatus() == 0) {
            return R.error("账号已禁用");
        }

        // 6.登录成功,将员工 id 存入 Session 并返回登录成功结果
        request.getSession().setAttribute("employee", emp.getId());
        return R.success(emp);
    }
}

上述在使用 MyBatis Plus 进行查询时涉及到了一些相关知识,简单分析如下:

  1. LambdaQueryWrapper<T>:LambdaQueryWrapper 是 MyBatis Plus 提供的一个查询条件构造器,用于在查询时使用 Lambda 表达式来构建查询条件。它是一个泛型类,其中的泛型 T 用于指定查询的实体类型。并且调用了 LambdaQueryWrapper 的 eq() 方法,用于添加等于条件。即指定查询条件为:Employee 实体的用户名字段等于给定的用户名。
  2. T getOne(Wrapper<T> queryWrapper):getOne() 是 MyBatis Plus 实现的方法,用于查询满足条件的单个实体。根据传入的 LambdaQueryWrapper 对象,它将根据指定的查询条件从数据库中获取符合条件的实体。

值得注意的是,上面的写法如果在我们的项目中运行便会报错,报错信息如下:

ERROR 21812 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'ew.sqlSegment != null and ew.sqlSegment != '' and ew.nonEmptyOfWhere'. Cause: org.apache.ibatis.ognl.OgnlException: sqlSegment [java.lang.ExceptionInInitializerError]] with root cause
java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.lang.Class java.lang.invoke.SerializedLambda.capturingClass accessible: module java.base does not "opens java.lang.invoke" to unnamed module @68999068

这个错误和 Java 的模块化系统(Jigsaw),尤其是 Java 9 及之后版本引入的强封装性有关。这个错误的原因是我们用了 JDK 8 引入的 Lambda 表达式和函数引用,这在 MyBatis Plus 中被广泛用于构建动态 SQL 查询,其实也就是因为使用了 LambdaQueryWrapper。然而,MyBatis Plus 在通过 LambdaQueryWrapper 执行这些操作时需要通过反射访问 java.lang.invoke.SerializedLambda 类的一些字段,但是由于 Java 的模块化系统的安全限制,这些字段并不能被反射访问。

最简单的解决办法就是将我们的 JDK 版本降低到 JDK 1.8,但是笔者这里选择继续使用 JDK 11,那就不得不放弃使用 LambdaQueryWrapper,而是使用更传统的方式来构建查询,但这可能会失去一些 MyBatis Plus 提供的便利性。

例如,我们可以通过 MyBatis Plus 的 QueryWrapper,而不是 LambdaQueryWrapper 来进行条件构建:

@PostMapping("/login")
public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee) {
    // 1.将页面提交的密码进行 MD5 加密处理
    String password = employee.getPassword();
    password = DigestUtils.md5DigestAsHex(password.getBytes());

    // 2.根据用户名查询数据库
    /*LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(Employee::getUsername,employee.getUsername());
    Employee emp = employeeService.getOne(queryWrapper);*/

    QueryWrapper<Employee> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("username", employee.getUsername());
    Employee emp = employeeService.getOne(queryWrapper);

    // 3.如果没有查询到则返回登录失败结果
    if (emp == null) {
        return R.error("登陆失败");
    }

    // 4.进行密码比对,如果不一致则返回登录失败结果
    if (!emp.getPassword().equals(password)) {
        return R.error("登陆失败");
    }

    // 5.查看员工状态,如果为已禁用状态,则返回员工已禁用结果
    if (emp.getStatus() == 0) {
        return R.error("账号已禁用");
    }

    // 6.登录成功,将员工 id 存入 Session 并返回登录成功结果
    request.getSession().setAttribute("employee", emp.getId());
    return R.success(emp);
}

可以看到,我们需要手动提供数据库中的列名 “username”,而不是使用函数引用 Employee::getUsername。虽然这样可以避免反射访问 java.lang.invoke.SerializedLambda,但这样的代码可能会更难维护,因为它不再具有类型安全性,并且如果数据库的列名改变了,我们也需要手动修改代码。

为了避免上面的问题,还有一个解决方案就是使用 JVM 参数来开放 java.lang.invoke 模块:

--add-opens java.base/java.lang.invoke=ALL-UNNAMED

这会允许所有未命名的模块访问 java.lang.invoke

3.功能测试

下面启动应用,再次访问 http://localhost:8080/static/backend/page/login/login.html 进行登陆测试,账户密码分别为 admin 和 12346。

首先使用一个错误的密码进行测试,结果如下:

可以看到响应失败了,我们可以在密码比对处打上断点,就能明显看到是因为密码比对失败:

换成正确的用户名和密码就能正确进入后台管理首页,但遗憾的是页面访问失败:

从 URL 可以看出登陆成功后跳转到了 “/backend/index.html”这是因为当时瑞吉外卖的项目静态文件是直接放在资源目录 resources 下的,而我们是放在 resources/static 目录下,这样更加符合规范。所以只需要对应修改 static/backend/page/login/login.html 中的登陆成功后的跳转页面为 /static/backend/index.html 即可。

重启应用再次测试就能成功跳转到主页了:

在,后端代码中我们返回了 R.success(emp),传入的参数就是对象信息,最终会被赋值给 R 类中的 data 属性,前端接收到响应对象后会将用户信息转为 JSON 数据存储在浏览器,关键代码见下图:

那么存储的信息在哪儿呢?我们可以通过浏览器打开调试工具(F12),在 Application 页面的 Storage 页面中找到:

4.分析后台系统首页构成

下面简单分析一些会面会用到的前端页面的关键部分,有利于后期开发。

其中的左侧菜单项被定义在 static/backend/index.html 中的如下位置:

当我们点击菜单栏的时候又是如何进行对应页面的切换呢?

可以看到,当点击左侧对应的列表项时,会触发一个 menuHandle(item,false) 函数,并传入了对应的 item 对象。追踪到下面的 menuHandle() 函数:

从上图中圈出部分可以看到,通过 item 对象获得了对应的 url 信息,然后通过 iframeUrl 的方式显示了一个新的页面。追踪到 iframeUrl 位置处:

可见,其实就是使用 item.url 对应的信息赋值给了默认的 “page/member/list.html”也就是我们看到的默认的员工页面,那 iframeUrl 是在何处被具体用到呢?接着向上追踪到如下位置:

不难看出,其实就是在页面的空白处创建了一个 iframe,具体的内容就是由 iframeUrl 对应请求传回的数据。

那么很容易就能想到,如果我们将 iframeUrl 的默认值进行修改,那么对应的就会出现我们想要的内容。下面进行一个简单测试,将 iframeUrl 的默认值修改为 “https://www.javgo.cn”,然后刷新网页对应就会出现该地址的页面:

注意:上述只是为了测试,笔者将地址修改为了个人博客地址,胖友测试完记得修改为原来的默认页面 page/member/list.html 哈。

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

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

相关文章

Baumer工业相机堡盟工业相机IO介绍与配置

Baumer工业相机堡盟工业相机IO介绍与配置 Baumer工业相机Baumer工业相机IO的作用Baumer工业相机IO的作用Baumer工业相机IO上点连 Baumer工业相机 Baumer工业相机堡盟相机是一种高性能、高质量的工业相机&#xff0c;可用于各种应用场景&#xff0c;如物体检测、计数和识别、运…

Android基础复习:Service组件详解

Android基础复习&#xff1a;Service组件详解 概况 Service组件是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动&#xff0c;而且即使用户切换到其他应用&#xff0c;服务仍将在后台继续运行。此外&#xff0c;组件可通过绑定到服务与之进…

【动手学深度学习】现代卷积神经网络汇总

文章目录 1 LeNet2 AlexNet3 VGG4 NiN5 GoogLeNet6 ResNet7 DenseNet 本文为作者阅读学习李沐老师《动手学深度学习》一书的阶段性读书总结&#xff0c;原书地址为&#xff1a;Dive into Deep Learning。 1 LeNet 网络结构 实现代码 net nn.Sequential(nn.Conv2d(1, 6, kern…

springboot+vue社区医院管理服务系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的社区医院管理服务系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1…

从C出发 32 --- 自定义数据类型(上)

字节 指的就是 byte , 而一个 byte 占用 8 位&#xff0c; 在 C 语言里面有没有 直接提供 表示 8 位的数据类型&#xff1f; char 最小的整型&#xff0c;就可以表示 8 位的数据类型 char 的取值范围 -128 - 127 一个字节的取值范围是 0 - 25…

RK3308B部署mobilenetv2_ssdlite

目录 1. 在PC端运行mobilenetv2_ssdlite模型1.1 安装NCNN和Opencv1.1.1 安装NCNN1.1.2 安装Opencv 1.2 运行mobilenetv2_ssdlite模型 2. 交叉编译部署到RK3308B板子上并运行模型2.1 交叉编译NCNN和Opencv2.1.1 交叉编译Opencv2.1.2 交叉编译ONNX 2.2 交叉编译mobilenetv2_ssdli…

总结850

学习目标&#xff1a; 月目标&#xff1a;5月&#xff08;张宇强化前10讲&#xff0c;背诵15篇短文&#xff0c;熟词僻义300词基础词&#xff09; 周目标&#xff1a;张宇强化前3讲并完成相应的习题并记录&#xff0c;英语背3篇文章并回诵 每日必复习&#xff08;5分钟&#…

深度学习环境配置系列文章(五):配置Docker深度学习开发环境

深度学习环境配置系列文章目录 第一章 专业名称和配置方案介绍 第二章 Anaconda配置Python和PyTorch 第三章 配置VS Code和Jupyter的Python环境 第四章 配置Windows11和Linux双系统 第五章 配置Docker深度学习开发环境 第五章文章目录 深度学习环境配置系列文章目录前言一, Do…

AI工具分享第二期:11款国内外AI绘画提示词工具整理

工具整理自未来百科AI工具箱&#xff0c;更多提示词工具可自行寻找 Midjourney中文教程 Midjourney 学习导航 PromptHero 描述 通过 DALL-E、Stable Diffusion、Midjourney 等 AI 模型搜索数以百万计的艺术图像… PromptDen AI 在线社区促使爱好者联系、协作和分享想法。 …

支付系统设计三:渠道网关设计07-后置处理

文章目录 前言一、订单数据更新1. 领域模型更新服务工厂2. 聚合创建工厂2.1 数据库更新服务2.2 聚合创建工厂 二、限流渠道入队三、异步通知1. 判断是否需要通知2. 组装异步通知报文3. 获取异步通知协议类型3. 异步通知 总结 前言 本篇将继业务处理之后的后置处理逻辑进行介绍&…

瑞吉外卖 - 后台系统退出功能(4)

某马瑞吉外卖单体架构项目完整开发文档&#xff0c;基于 Spring Boot 2.7.11 JDK 11。预计 5 月 20 日前更新完成&#xff0c;有需要的胖友记得一键三连&#xff0c;关注主页 “瑞吉外卖” 专栏获取最新文章。 相关资料&#xff1a;https://pan.baidu.com/s/1rO1Vytcp67mcw-PD…

瑞吉外卖 - 项目介绍(1)

某马瑞吉外卖单体架构项目完整开发文档&#xff0c;基于 Spring Boot 2.7.11 JDK 11。预计 5 月 20 日前更新完成&#xff0c;有需要的胖友记得一键三连&#xff0c;关注主页 “瑞吉外卖” 专栏获取最新文章。 相关资料&#xff1a;https://pan.baidu.com/s/1rO1Vytcp67mcw-PD…

CSS盒子模型、表格标签(table)、表单标签(form)

盒子&#xff1a;页面中所有的元素&#xff08;标签&#xff09;&#xff0c;都可以看做是一个 盒子&#xff0c;由盒子将页面中的元素包含在一个矩形区域内&#xff0c;通过盒子的视角更方便的进行页面布局 盒子模型组成&#xff1a;内容区域&#xff08;content&#xff09;…

Qt扫盲-QScatterSeries理论总结

QScatterSeries理论总结 一、概述二、使用三、扩展四、扩展使用1.创建描述散点图对象2. 对散点图像添加值3. 自定义散点4. 将绘图设备与散点图对象联系5. 设置坐标轴6. 将绘图设备与GUI控件绑定并显示 一、概述 QScatterSeries 类以散点图的形式呈现数据。散点数据在图表上显示…

基于jdk1.8的Java服务监控和性能调优

JVM的参数类型 X参数 非标准参数-Xint: 解释执行-Xcomp: 第一次使用就编译成本地代码-Xmixed: JVM自己来决定是否编译成本地代码 默认使用的是mixed mode 用的不多, 只需要做了解, 用的比较多的是XX参数 XX参数 非标准化参数相对不稳定主要用来JVM调优和Debug Boolean: …

Vivado综合属性系列之一 ASYNC_REG

目录 一、属性简介 二、示例 2.1 工程说明 ​ ​2.2 工程代码 ​ ​2.3 生效确认 一、属性简介 ASYNC_REG属性的作用对象为寄存器&#xff0c;寄存器添加该属性后&#xff0c;即表明寄存器的数据输入口D接收的是来自异步时钟触发器的数据或是该寄存器在一个同步链中属于…

【CSS系列】第九章 · CSS定位和布局

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…

Uni-app 离线打包 apk

Uni-app 离线打包 apk 1. Android Studio 下载 Android Studio官网 2. HBuilderX下载 HBuilderX下载 3. App离线SDK下载 Android 离线SDK - 正式版 下载后解压文件&#xff0c;将 HBuilder-Integrate-AS 重命名 build-template 并拷贝到一个专门打包用的文件夹下作为打包…

一行代码绘制高分SCI限制立方图

一、概述 Restricted cubic splines (RCS)是一种基于样条函数的非参数化模型&#xff0c;它可以可靠地拟合非线性关系&#xff0c;可以自适应地调整分割结点。在统计学和机器学习领域&#xff0c;RCS通常用来对连续型自变量进行建模&#xff0c;并在解释自变量与响应变量的关系…

抑梯度异常初始化参数(防止梯度消失和梯度爆炸)

这里设置3种参数初始化的对比&#xff0c;分别是&#xff1a;全初始化为0、随机初始化、抑梯度异常初始化。 首先是正反向传播、画图、加载数据所需的函数init_utils.py&#xff1a; # -*- coding: utf-8 -*-import numpy as np import matplotlib.pyplot as plt import sklea…