用React给XXL-JOB开发一个新皮肤(三):实现登录页和Layout骨架

news2024/9/27 19:17:46

目录

  • 一. 简述
  • 二. 接口服务调整
    • 2.1. 登录接口
    • 2.2. 登出接口
    • 2.3. 修改密码接口
    • 2.4. 修改配置文件
  • 三. 前端HTTP 请求
  • 四. 登录页面
    • 4.1. 搭建登录页面
    • 4.2. 对接登录接口
  • 五. Layout 骨架
    • 5.1. 搭建骨架
    • 5.2. Header
    • 5.3. 修改密码
    • 5.4. 退出登录
  • 六. 其他

一. 简述

上一篇文章我们介绍了项目的目录规划、修改vite 配置并且创建了项目的路由信息。此篇文章我们会先实现登录页面和管理页面的 Layout 骨架。

二. 接口服务调整

xxl-job-adminIndexController 中有我们需要的登录和登出接口;但是从接口输出方式可以看出来,并不符合前后端分离的模式,所有我们这里需要做兼容。另外还需考虑的是在不修改 xxl-job-admin 中的代码(不然我们后面对照功能的时候不方便)的前提下,如何可以给我们现在的项目提供接口呢?

所有我这里创建了一个新的项目 xxl-job-admin-new,此时我们项目目录结构如下:
在这里插入图片描述
在这个项目中,maven 依赖相较 xxl-job-admin添加 lombokvalidation这两个,其他的不变;另外我添加全局异常处理和一些必要class,结构如下:
在这里插入图片描述

2.1. 登录接口

对于登录接口也无大的改动,仅将之前的POST表单接口改为 POST JSON 方法提交,并添加了表单验证。代码如下:

@Slf4j
@RestController
@RequestMapping("user")
public class UserController {

  private final XxlJobService xxlJobService;

  private final LoginService loginService;

  public UserController(XxlJobService xxlJobService, LoginService loginService) {
    this.xxlJobService = xxlJobService;
    this.loginService = loginService;
  }

  @PostMapping("login")
  @PermissionLimit(limit=false)
  public ReturnT<UserLoginResponseDto> loginDo(@RequestBody @Validated UserLoginRequestDto param, HttpServletRequest request, HttpServletResponse response){
    return new ReturnT<>(loginService.login(param, request, response));
  }
}

这里的@PermissionLimit是做鉴权的,具体可以看PermissionInterceptor拦截器。

这里的登录逻辑也很简单,先校验登录表单,然后通过用户名称获取用户实体XxlJobUser,密码比对;接着将XxlJobUser转为十六进制的字符串;最后将登录信息写入 Cookie 并返回。

这里不做详细的 Java 代码分析,后面有时间在写一个专门把 xxl-job 源码分析的专栏吧。

2.2. 登出接口

登出接口也不变,就是清除 Cookie

@Slf4j
@RestController
@RequestMapping("user")
public class UserController {

  private final XxlJobService xxlJobService;

  private final LoginService loginService;

  public UserController(XxlJobService xxlJobService, LoginService loginService) {
    this.xxlJobService = xxlJobService;
    this.loginService = loginService;
  }

  @GetMapping("logout")
  @PermissionLimit(limit=false)
  public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
    return new ReturnT<>(loginService.logout(request, response));
  }
}

2.3. 修改密码接口

修改密码的接口,改为 Get 请求,代码如下 :

@Slf4j
@RestController
@RequestMapping("user")
public class UserController {

  private final XxlJobService xxlJobService;

  private final LoginService loginService;

  public UserController(XxlJobService xxlJobService, LoginService loginService) {
    this.xxlJobService = xxlJobService;
    this.loginService = loginService;
  }

  @GetMapping("updatePwd")
  public ReturnT<String> updatePwd(HttpServletRequest request, @RequestParam("password") String password){
    password = password.trim();
    if (!(password.length()>=4 && password.length()<=20)) {
      return new ReturnT<String>(PASSWORD_LEN_ERROR, PASSWORD_LEN_ERROR.getMsg());
    }

    // md5 password
    String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());

    // update pwd
    XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginServiceImpl.LOGIN_IDENTITY_KEY);

    // 修改
    loginService.updateUser(loginUser.getId(), md5Password);
    return new ReturnT<>("密码修改成功");
  }
}

这里的代码,仅修改了loginService.updateUser(loginUser.getId(), md5Password);将修改的逻辑下放到了 service 层。

2.4. 修改配置文件

最后我们需要将application.properties 中关于 freemarkerresources 的配置移除,并将启动端口改为 9090;另外还需要将 logback.xml 中的日志文件修改一个其他的名字。

此时我们启动项目是无法启动,因为报一个i18n 的错误,此时需要我们在 XxlJobScheduler.java 中将 iniI8n()的初始化方法注释就可以了。
在这里插入图片描述
好了,现在我们可以启动 xxl-job-admin-new 的服务了。
在这里插入图片描述

上面的部分是关于后端接口修改,不太理解的前端同学可以直接访问项目启动后端服务就可以了!

三. 前端HTTP 请求

这里我们是用的是 axios 请求接口,一般来说大家都会封装下,我在 naive 的开源项目naive-ui-admin 中看到一个封装很不错的 axios 请求工具,我在此基础上修改了下封装到了 utils 中的 request.ts工具类。

这里封装比较麻烦,但是很好用,有时间可以开一篇文章详细介绍下,如何封装的。

在之前文章中,我们在 src 目录中有一个 api 的目录,就是专门存放,我们调用后端接口的 api 函数,这里我们将用户相关的操作都放到 user.ts中。

import {User} from "@/types";
import {https} from "@/utils/request.ts";

namespace UserApi {

  /**
   * 登录
   * @param param
   * @constructor
   */
  export const UserLogin = (param: User.UserLoginFormProp): Promise<User.UserLoginResultProp> => {
    return https.request({
      url: '/user/login',
      method: 'post',
      data: param
    })
  }

  /**
   * 退出登录
   * @constructor
   */
  export const UserLogout = (): Promise<string> => {
    return https.request({
      url: '/user/logout',
      method: 'get'
    })
  }

  /**
   * 修改密码
   * @param pwd
   * @constructor
   */
  export const UpdatePassword = (pwd: string): Promise<string> => {
    return https.request({
      url: '/user/updatePwd',
      method: 'get',
      params: {password: pwd}
    })
  }
}

export default UserApi

这里面的User.UserLoginFormPropUser.UserLoginResultProp是登录的输入和输出模型定义(文章后面会有定义的具体属性)。

这里我们还需要在vite.config.ts中开启代理:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from "path";

// https://vitejs.dev/config/
export default defineConfig({
  
  server: {
    port: 9091,
    proxy: {
      "/api": {
        target: "http://localhost:9090/xxl-job-admin",
        changeOrigin: true, // 跨域设置
        rewrite: (path) => path.replace(/^\/api/, ""), // 将 api 前缀去掉
      },
    },
  },
})

四. 登录页面

这里的登录页面我们这里借鉴 Ant Design Pro的登录页面,略作修改就可以了。
在这里插入图片描述

4.1. 搭建登录页面

这里登录页面就是一个 form 表单,直接使用https://ant-design.antgroup.com/components/form-cn的表单组件。代码如下:

import styled from "@emotion/styled";
import {Button, Card, Checkbox, Form, Input, message, Typography} from "antd";
import {LockOutlined, UserOutlined} from "@ant-design/icons";
import {User} from "@/types";
import {useNavigate} from "react-router-dom";
import {DEFAULT_HOME_PATH} from "@/config/constant.ts"; // 定义的一些静态常量

const LoginPage = () => {

  const navigate = useNavigate(); // 路由切换 hooks
  const [form] = Form.useForm<User.UserLoginFormProp>();

  const onSubmit = () => {
    form.validateFields().then(value => {
      console.log("value => ", value);
      // TODO 调用登录接口
    })
  }


  return <Container>
    <Card className="login-card" style={{width: 400}}>
      <Typography.Title level={3} style={{textAlign: 'center', marginBottom: 40}}>任务调度中心</Typography.Title>
      <Form
        name="normal_login"
        className="login-form"
        initialValues={{ remember: true }}
        form={form}
      >
        <Form.Item
          name="username"
          rules={[{ required: true, message: '请输入账号名称!' }]}
        >
          <Input prefix={<UserOutlined className="site-form-item-icon" />} placeholder="请输入登录账号" />
        </Form.Item>
        <Form.Item
          name="password"
          rules={[{ required: true, message: '请输入账号密码!' }]}
        >
          <Input prefix={<LockOutlined className="site-form-item-icon" />} type="password" placeholder="请输入登录密码"/>
        </Form.Item>
        <Form.Item className="form-login-btn">
          <Form.Item name="ifRemember" valuePropName="unchecked" noStyle>
            <Checkbox>记住密码</Checkbox>
          </Form.Item>
          <Button type="primary" className="login-form-button" onClick={onSubmit}>登录</Button>
        </Form.Item>
      </Form>
    </Card>
  </Container>
}

这里的<Container>标签是通过@emotion/styled创建样式化组件。

const Container = styled.div`
    display: flex;
    flex-direction: column;
    align-items: center;
    height: 100vh;
    overflow: auto;
    background-image: url('https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/V-_oS6r-i7wAAAAAAAAAAAAAFl94AQBr');
    background-size: 100% 100%;
    .login-card {
      position: absolute;
      top: 20%;
      .ant-card-body {
          padding-top: 8px;
          .form-login-btn {
              .ant-form-item-control-input-content {
                  display: flex;
                  flex-direction: row;
                  justify-content: space-between;
                  align-items: center;
              }
          }
      }
  }
`

运行项目,效果如下:
在这里插入图片描述

4.2. 对接登录接口

我们在 types目录添加一个 user.type.ts 文件,存放用户相关的接口模型(这个模型就是上面定义的)。

namespace User {
  // UserLoginFormProp 用户登录表单属性
  export interface UserLoginFormProp {
    username: string; // 用户名
    password: string; // 密码
    ifRemember: boolean; // 记住密码
  }
  
  // UserLoginResultProp 用户登录返回属性
  export interface UserLoginResultProp {
    userId: number; // 用户名
    username: string; // 密码
    role: number;
    token: string;
    permission: string[];
  }
}

export default User;

最后使用 index.ts导出

import User from "@/types/user.type.ts";

export type {
  User
}

这里对接登录接口,我们使用了 ahooks 中的 useRequest ,具体使用就是官方文档中有详细的介绍。https://ahooks.gitee.io/zh-CN/hooks/use-request/index

下面看一下如何借助 useRequest 轻松的调用我们的接口:

const loginRequest = useRequest(UserApi.UserLogin, {
  manual: true, // 表示手动触发
  onSuccess: (result) => {
    console.log(result);
    message.success('登录成功');
    navigate(DEFAULT_HOME_PATH); // 跳转到首页
  }
})

const onSubmit = () => {
  form.validateFields().then(value => {
    loginRequest.run(value) // 手动调用登录接口
  })
}

最后我们看一下浏览器的Cookie
在这里插入图片描述

五. Layout 骨架

整个 Layout 骨架主要分为左侧菜单、Header 和内容三部分,这里我们直接使用 antd 实现骨架。

5.1. 搭建骨架

直接上代码:

<Container>
  {/* 菜单 */}
  <Layout.Sider trigger={null} collapsible collapsed={collapsed}>
    <div className="xxl-logo-vertical" />
    <Menu
      theme="dark"
      mode="inline"
      selectedKeys={selectedKeys}
      onClick={({key}) => clickMenu(key)}
      items={[
        {
          key: '/xxl-job/report',
          icon: <BarChartOutlined />,
          label: '运行报表',
        },
        {
          key: '/xxl-job/task',
          icon: <SnippetsOutlined />,
          label: '任务管理',
        },
        {
          key: '/xxl-job/dispatch',
          icon: <CalendarOutlined />,
          label: '调度日志',
        },
        {
          key: '/xxl-job/executor',
          icon: <MenuOutlined />,
          label: '执行器管理',
        },
        {
          key: '/xxl-job/user',
          icon: <UserOutlined />,
          label: '用户管理',
        },
        {
          key: '/xxl-job/course',
          icon: <BulbOutlined />,
          label: '使用教程',
        },
      ]}
    />
  </Layout.Sider>
  {/* 内容 */}
  <Layout>
    {/* 头 */}
    <Layout.Header style={{ padding: 0, background: colorBgContainer, display: "flex" }}>
      <Button
        type="text"
        icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
        onClick={() => setCollapsed(!collapsed)}
        style={{
          fontSize: '16px',
          width: 64,
          height: 64,
        }}
      />
      <div style={{flex: '1 1 0%'}} />
      <div className="header-right-content">
        <div style={{height: '100%'}}>
          <div className="header-right-content-inner">
            <Dropdown key="translate" menu={{ items: translates}} placement="bottom" arrow={{ pointAtCenter: true }}>
              <div className="ant-dropdown-trigger-str">
                <TranslationOutlined />
              </div>
            </Dropdown>
            <Dropdown key="items" menu={{ items, onClick: logoutClick}} placement="bottom" arrow={{ pointAtCenter: true }}>
              <div className="ant-dropdown-trigger-logout">
                <Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
                <span>管理员</span>
              </div>
            </Dropdown>
          </div>
        </div>
      </div>
    </Layout.Header>
    {/* 内容 */}
    <Layout.Content style={{
      margin: '16px 16px',
      padding: 24,
      minHeight: 280,
      background: colorBgContainer,
      borderRadius: borderRadiusLG,
    }}>
      <Outlet />
    </Layout.Content>
  </Layout>
  <Modal title="修改密码" open={showModel} onOk={okUpdatePassword} onCancel={closeUpdatePassword}>
    <Input placeholder="请输入新密码" value={password} onChange={e => setPassword(e.target.value)}/>
  </Modal>
</Container>

这里的 Menu 菜单涉及到一个点击菜单切换路由的功能,代码如下:

const navigate = useNavigate(); // 路由切换 hooks
const [selectedKeys, setSelectedKeys] = useState<string[]>([DEFAULT_MENU_KEY]); // 默认路由

const clickMenu = (data: string) => {
  setSelectedKeys([data]) // 选中菜单
  navigate(data) // 切换路由
}

路由切换提现为组件切换,主要是通过<Outlet />,前面的文章已经介绍过了。

5.2. Header

接着我们这个需要在介绍下,Header 部分的代码,这里包含一个菜单的收缩按钮,另一个是就是一个用户头像(包含修改密码和退出登录);还有一个切换语言的下拉组件,后续还会添加一个主题切换的下拉按组件。这两个大同小异,代码如下:

const translates: MenuProps['items'] = [
    {
      key: 'chine',
      label: (
        <span>
          <span role="img" aria-label="English" style={{marginRight: 8}}>🇨🇳</span>
          中文
        </span>
      )
    },
    {
      key: 'english',
      label: (
        <span>
          <span role="img" aria-label="English" style={{marginRight: 8}}>🇺🇸</span>
          English
        </span>
      )
    }
  ];

  const items: MenuProps['items'] = [
    {
      key: '1',
      label: '修改密码',
      icon: <EditOutlined />
    },
    {
      key: '2',
      label: '退出登录',
      icon: <LogoutOutlined />,
      danger: true
    }
  ];
  
  // 用户头像下拉组件的点击事件
  const logoutClick: MenuProps['onClick'] = (e) => {
    if (e.key === '2') {
      logoutRequest.run(); // 退出登录
    } else if (e.key === '1') {
      setShowModel(true); // 修改密码的 model 弹窗控制事件
    }
  };

5.3. 修改密码

修改密码这里是通过模态框弹出一个Input 组件,用户输出新的密码,调用修改密码接口执行操作的。

<Modal title="修改密码" open={showModel} onOk={okUpdatePassword} onCancel={closeUpdatePassword}>
  <Input placeholder="请输入新密码" value={password} onChange={e => setPassword(e.target.value)}/>
</Modal>

对应的点击事件代码如下:

const [showModel, setShowModel] = useState(false);
const [password, setPassword] = useState<string>("");

// 更新密码
const updatePasswordRequest = useRequest(UpdatePassword, {
  manual: true,
  onSuccess: (res) => {
    message.success(res);
    setShowModel(false);
  }
})

// 模态框 确定按钮事件
const okUpdatePassword = () => {
  updatePasswordRequest.run(password);
}

// 模态框 取消按钮事件
const closeUpdatePassword = () => {
  setShowModel(false);
  setPassword(''); // 这里需要清空 input 框内容
}

5.4. 退出登录

退出登录,后端接口会将当前的 cookie清除,前端只需要调用退出登录的接口,并将返回登录页面,代码如下:

const logoutRequest = useRequest(UserLogout, {
  manual: true,
  onSuccess: (res) => {
    message.success(res);
    navigate(LOGIN_PAGE);
  }
})

好了,这个部分的代码就搞定了,最后我们启动运行,预览如下:
在这里插入图片描述

六. 其他

上面代码并没有全不展示出来,仅展示重要的代码。需要查看完整代码可以查看仓库:https://gitee.com/molonglove/xxl-job/tree/2.4.0.1/。

下一篇文章,我们将实现用户管理部分的代码页面和接口。

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

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

相关文章

【栈】【字符】Leetcode 20 有效的括号

【栈】【字符】Leetcode 20 有效的括号 解法1 栈的操作&#xff08;先进后出&#xff09; ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 解法1 栈的操作&#xff08;先进后出&#xff09; 新建栈&#xff1a;Stack<C…

Oracle篇—实例中和name相关参数的区别和作用

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux&#xff0c;也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&#xff0c;并且也会默默的点赞收藏加关注❣…

数据挖掘实战-基于机器学习的电商文本分类模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

【算法分析与设计】跳跃游戏

题目 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - …

微信小程序快速入门02(含案例)

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java项目分享》 《RabbitMQ》《Spring》《SpringMVC》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 前言一、页面导航1.…

第七讲 单片机驱动彩色液晶屏 控制RA8889软件:显示文字:Part3.自建字库

单片机驱动TFT彩色液晶屏系列讲座 目录 第一讲 单片机最小系统STM32F103C6T6通过RA8889驱动彩色液晶屏播放视频 第二讲 单片机最小系统STM32F103C6T6控制RA8889驱动彩色液晶屏硬件框架 第三讲 单片机驱动彩色液晶屏 控制RA8889软件:如何初始化 第四讲 单片机驱动彩色液晶屏 控…

用通俗易懂的方式讲解:一文讲透主流大语言模型的技术原理细节

大家好&#xff0c;今天的文章分享三个方面的内容&#xff1a; 1、比较 LLaMA、ChatGLM、Falcon 等大语言模型的细节&#xff1a;tokenizer、位置编码、Layer Normalization、激活函数等。 2、大语言模型的分布式训练技术&#xff1a;数据并行、张量模型并行、流水线并行、3D …

P1042 [NOIP2003 普及组] 乒乓球————C++

目录 [NOIP2003 普及组] 乒乓球题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 解题思路Code运行结果 [NOIP2003 普及组] 乒乓球 题目背景 国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革&#xff0c;以推动乒乓球运动在全球的普及。其中 …

计算机毕业设计-----SSH企业人力资源管理系统

项目介绍 企业人力资源管理系统&#xff0c;分为超级管理员与普通管理员两种角色,超级管理员可以对普通管理员进行添加、删除等操作&#xff1b; 超级管理员主要功能有&#xff1a; 部门管理、员工管理、招聘管理、培训管理、奖惩管理、薪资管理、用户信息修改、系统管理&…

jmap使用

jmap 是 Java 虚拟机 (JVM) 中的一个命令行工具&#xff0c;用于生成堆转储。这个工具对于诊断内存问题、分析内存占用情况等非常有用。 jmap 官方文档 bash: jmap: command not found 命令找不到 # jmap -dump <pid>jmap -dump 137886 安装一下java-devel yum -y in…

[②C++ Boost]: Boost库编译,arm交叉编译方法

前言 Boost是十分实用的C库&#xff0c;如果想在arm环境下使用&#xff0c;就需要自己下载源码编译&#xff0c;本篇博客就记录下Boost库的编译方法。 下载Boost源码 Boost源码的下载路径可以使用&#xff1a;https://sourceforge.net/projects/boost/files/boost/ 编译 …

计算机毕业设计----SSH实现简单在线听音乐收藏管理系统

项目介绍 项目分为管理员与普通用户两种角色&#xff0c; 管理员角色包含以下功能&#xff1a; 管理员登录,用户管理,歌曲管理等功能。 用户角色包含以下功能&#xff1a; 按分类查看,添加歌单,用户登录等功能。 环境需要 1.运行环境&#xff1a;最好是java jdk 1.8&…

基于SSM中小型医院管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

C/S架构,集成三维影像后处理功能,自主版权的一套医院PACS系统源码

一、PACS简介 PACS&#xff08;PictureArchivingandCommunicationsSystem&#xff09;即图像存储与传输系统&#xff0c;是应用于医院的数字医疗设备如CT、MR&#xff08;磁共振&#xff09;、US&#xff08;超声成像&#xff09;、X光机、DSA&#xff08;数字减影&#xff09…

Qt 调试系统输出报警声以及添加资源

文章目录 前言一、方法1 使用 Qsound1.添加都文件 直接报错2.解决这个错误 添加 QT multimedia3. 加入代码又遇到新的错误小结 二、第二种方法1.引入库2.添加资源2.1依次点击Qt--->Qt Resource File--->Choose2.2给资源文件起个名字&#xff0c;如&#xff1a;res&#…

数据结构实战:变位词侦测

文章目录 一、实战概述二、实战步骤&#xff08;一&#xff09;逐个比较法1、编写源程序2、代码解释说明&#xff08;1&#xff09;函数逻辑解释&#xff08;2&#xff09;主程序部分 3、运行程序&#xff0c;查看结果4、计算时间复杂度 &#xff08;二&#xff09;排序比较法1…

MySQL的各种日志

目录 一、错误日志 二、二进制日志 1、介绍 2、作用 3、相关信息 4、日志格式 5、查看二进制文件 6、二进制日志文件删除 三、查询日志 四、慢日志 一、错误日志 记录MySQL在启动和停止时&#xff0c;以及服务器运行过程中发生的严重错误的相关信息&#xff0c;当数据库…

靶场实战(12):OSCP备考之VulnHub SEPPUKU

打靶思路 资产发现 主机发现服务发现&#xff08;端口、服务、组件、版本&#xff09;漏洞发现&#xff08;获取权限&#xff09; 21端口/FTP服务 组件漏洞口令漏洞80端口/HTTP服务 组件漏洞URL漏洞&#xff08;目录、文件&#xff09;7080端口/HTTPS服务 组件漏洞URL漏洞&…

【博士每天一篇论文-理论分析】Dynamical systems, attractors, and neural circuits

阅读时间&#xff1a;2023-11-19 1 介绍 年份&#xff1a;2016 作者&#xff1a;Paul Miller 马萨诸塞州沃尔瑟姆市布兰代斯大学Volen国家复杂系统中心 期刊&#xff1a; F1000Research 引用量&#xff1a;63 这篇论文主要关注神经回路中的动力系统和吸引子。作者指出神经回路…

操作系统-操作系统的特征(并发 共享 虚拟 异步 之间关系)

文章目录 总览操作系统的特征-并发操作系统的特征-共享并发和共享的关系操作系统的特征-虚拟操作系统的特征-异步小结 总览 操作系统的特征-并发 并行&#xff1a;同时做多个事件 并发&#xff1a;同一个时刻只有一个事件&#xff0c;但会切换事件&#xff0c;所以宏观上可能做…