猿客栈后台管理系统日志记录

news2024/11/26 16:46:10

目录

一、用户权限设置

前端逻辑

后端逻辑

二、登录界面逻辑

1、账号密码登录实现

前端逻辑

在Cookie中存储token的方法

在Cookie中存储和获取的token方法

后端逻辑

生成token工具类

2、手机号登录

前台逻辑

后台逻辑

补充:实现点击发送验证码120s倒计时功能

三、文章管理功能

1、实现批量删除

前端逻辑

后端逻辑

2、数据编辑实现表格数据回显

3、实现表格中动态显示不同数据的图片信息

四、图片上传功能

前端逻辑

后端逻辑

五、在Vue中封装axios请求

1、在src中创建utils目录 创建request.js

2、在src下再创建不同接口请求的js文件

3、在src下再创建一个index.js

4、在main.js中引入这个api中的index.js

5、调用方式

六、Echarts的基本引入

1、在Vue中导入Echarts

 2、不同图形的属性

3、补充  Echarts取数据

1、在js对象中获取所有的key值

2、在js对象中获取所有的value值

3、将js对象转为集合类型使其能够通过索引取数据

七、使用SpringBoot的拦截器拦截特定url

1、创建Iterceptor

2、在WebMvc中注入并添加

八、实现账户退出并清空token

1、在main.js中添加导航路由守卫

2、退出逻辑



一、用户权限设置

只有管理员才能对后台进行登录,在用户表中设置管理员属性admin,设置默认值为0,当这个值大于0时,表示为管理员权限,其中将一个账号设置为超级管理员,管理其他的普通管理员,所以在账号进行登录时,判断他的admin属性值,是否能够进行登录

前端逻辑

先获取当前登录用户的token,以及要修改的这一行数据,作为参数传递给后端,根据返回值判断是否允许修改

后端逻辑

  1. 先使用JWT工具类解析当前的token值中的用户信息
  2. 判断token中的用户信息是否存在防止NPE
  3. 判断当前token中的用户是否是超级管理员,不是超级管理员返回fail
  4. 是超级管理员则对admin值进行修改

二、登录界面逻辑

1、账号密码登录实现

前端逻辑

使用element表单获取输入的数据,单击登录,将表单提交给后端,提交给后端后,后端会根据当前登录的账号创建一个token返回给前端,前端接收到token 将token存储进 Cookie中,接收到结果为真直接跳转到首页

在Cookie中存储token的方法

  1. 在Vue项目中安装 js-cookie       npm i js-cookie  
  2. 在项目中引入Cookie       import Cookie from 'js-cookie'
  3. 设置token存储进Cookie    Cookie.set('token',后端返回的token值)

在Cookie中存储和获取的token方法

  1. 在script中引入Cookie
  2. Cookie.get('token')

后端逻辑

根据登录的账户生成token并返回

@Service
public class LoginServiceImpl implements LoginService {
    //加密盐 防止md5被解密
    private static final String slat = "mszlu!@#";

    //登录功能需要查询用户表,将用户操作的service注入
    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Override
    public Result login(LoginParam loginParam) {
        /**
         * 1、检查参数是否合法
         * 2、根据用户名和密码在 user表中查询是否存在
         * 3、如果不存在 登陆失败
         * 4、登陆成功 使用JWT生成token 返回给前端
         * 5、将token放入redis 设置:(tokenuser 信息 设置过期时间)
         * (登录认证的时候 先认证token字符串是否合法 再去Redis认证是否存在)
         */
        //获取登陆的用户名和密码
        String username = loginParam.getUsername();
        String password = loginParam.getPassword();

        //判断账户对象或者密码是否为空
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)){
            return Result.fail(1200,"账户对象或密码为空");
        }

        //给密码加密
        password = DigestUtils.md5Hex(password + slat);

        //查询用户表中有没有对应的用户对象
        SysUser sysUser = userService.findUserInLog(username,password);

        if (sysUser == null){
            return Result.fail(1201,"用户名或密码错误!");
        }

        //如果是管理员登录才允许进入
        Integer admin = sysUser.getAdmin();
        if (admin >= 1){
            //用户存在生成对应的token
            String token = JWTUtils.createToken(sysUser.getId());

            //将token放入redis中 设置过期时间1天
            redisTemplate.opsForValue().set("TOKEN_"+token, JSON.toJSONString(sysUser), 1, TimeUnit.DAYS);
            return Result.success(token);
        }else {
            return Result.fail(3020,"对不起,当前用户权限不足!");
        }
    }
}

生成token工具类

public class JWTUtils {

    //JWT密钥
    private static final String jwtToken = "123456!@#$$";

    //创建一个token
    public static String createToken(Long userId){
        //B部分
        Map<String,Object> claims = new HashMap<>();
        claims.put("userId",userId);
        JwtBuilder jwtBuilder = Jwts.builder()
                //A部分
                .signWith(SignatureAlgorithm.HS256, jwtToken) // 签发算法,秘钥为jwtToken
                //设置B部分
                .setClaims(claims) // body数据,要唯一,自行设置
                .setIssuedAt(new Date()) // 设置签发时间
                .setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 60 * 1000));// 一天的有效时间
        //设置token完成
        String token = jwtBuilder.compact();
        return token;
    }

    public static Map<String, Object> checkToken(String token){
        try {
            //JWT 通过密钥 解析token
            Jwt parse = Jwts.parser().setSigningKey(jwtToken).parse(token);
            return (Map<String, Object>) parse.getBody();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;

    }
}

2、手机号登录

前台逻辑

同样使用表单构建 将当前用户输入的手机号发送给后端 当点击发送验证码时,将手机号发送给后端校验,校验通过后再申请发送验证码的接口,接收到后端发送的验证码先进行解密,在根据用户输入的验证码进行登录校验,校验成功将后端返回的token存储进Cookie中,跳转到首页。

后台逻辑

先接收前端发送的手机号查询到当前用户对象,先判断账号是否存在,如果不存在则提示先注册,在判断当前用户的权限是否允许登录,权限允许 则调用发送验证码接口,返回给前端加密的验证码,前端用户输入接收到的验证码点击登录后,再将当前的手机号发送给后端,生成token返回。

先在阿里云短信服务中申请签名和短信模板,获取阿里云accessKeyID的账号和密码,以及注册好的短信模板代码,调用接口

@Component
public class CodeUtils {
    //生成手机验证码工具类
    public boolean sendCode(String phoneNum,String templateCode,Map<String,Object> code) {
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI5tJX8MHTLx4mPGw5hNyN", "BTI4MSNNYq8Bl0KZ3mv449lmeBJhFl");

        IAcsClient client = new DefaultAcsClient(profile);
        //构建请求
        CommonRequest request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain("dysmsapi.aliyuncs.com");
        request.setSysAction("SendSms");
        request.setSysVersion("2017-05-25");

        //自定义的参数(手机号、验证码、签名、模板)
        request.putQueryParameter("PhoneNumbers", phoneNum);
        //签名
        request.putQueryParameter("SignName", "猿客栈后台登录");
        //模板
        request.putQueryParameter("TemplateCode", templateCode);
        //构建一个短信验证码

        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(code));


        try {
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
            //返回是否发送成功
            return response.getHttpResponse().isSuccess();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 随机生成6位验证码
     * @return
     */
    public String getCode(){
        Random random = new Random();

        StringBuffer builder = new StringBuffer();
        //循环6次生成验证码
        for (int i=0;i<6;i++){
            int code = random.nextInt(10);
            builder.append(code);
        }
        return builder.toString();
    }

    /**
     * 将验证码加密
     */
    public String md5String(String code){
        //将验证码加密
        StringBuffer reverse = new StringBuffer(code).reverse();
        String s = reverse.toString();
        Long i = Long.valueOf(s);
        i += 123456;
        return String.valueOf(i);
    }

}

LoginService

    @Override
    public Result loginByPhone(String phone) {
        //根据手机号查找用户对象并判断权限
        SysUser userByPhone = userService.getUserByPhone(phone);
        if (Objects.isNull(userByPhone)){
            return Result.fail(5000,"该手机号未注册!请先注册");
        }
        //创建token返回
        //用户存在生成对应的token
        String token = JWTUtils.createToken(userByPhone.getId());

        //将token放入redis中 设置过期时间1天
        redisTemplate.opsForValue().set("TOKEN_"+token, JSON.toJSONString(userByPhone), 1, TimeUnit.DAYS);
        return Result.success(token);
    }

UserService查看权限

    @Override
    public Result isLoginByPhone(String phoneNum) {
        SysUser sysUser = getUserByPhone(phoneNum);
        if (Objects.isNull(sysUser)){
            return Result.fail(2500,"手机号不存在! 请先注册!");
        }else if (sysUser.getAdmin() >= 1){
            //只允许管理员登录
            return Result.success("允许登录");
        }
        return Result.fail(500,"对不起,权限不足无法登陆!");

    }

    /**
     * 通过手机号查询用户对象
     * @param phoneNum
     * @return
     */
    @Override
    public SysUser getUserByPhone(String phoneNum) {
        QueryWrapper<SysUser> qw = new QueryWrapper<>();
        qw.eq("mobile_phone_number",phoneNum);
        SysUser sysUser = userMapper.selectOne(qw);
        return sysUser;
    }

补充:实现点击发送验证码120s倒计时功能

在表单中添加一个span 添加button 发送验证码 并且实现动态显示按钮内容

 绑定实体类

 动态文字显示

	//验证码提示信息动态显示
			getCodeText: function() {
				if (this.wait_timer > 0) {
					return "已发送";
				}
				if (this.wait_timer === 0) {
					this.showNum = false;
					return "重新发送验证码!";
				}
				if (this.wait_timer === false) {
					return "发送验证码";
				}
				if (this.userForm.tele === '') {
					return "手机号不能为空"
				}
			},

实现倒计时120s

//验证码等待
if (this.wait_timer > 0) {
	return false;
}
this.showNum = true;
this.wait_timer = 120;
var that = this;
var timer_interval = setInterval(function() {
	if (that.wait_timer > 0) {
		that.wait_timer--;
	} else {
		learInterval(timer_interval);
	}
}, 1000);

三、文章管理功能

1、实现批量删除

前端逻辑

要实现批量删除功能首先要在表单中添加selection类型的表格列,通过this.$refs.table.selection获取当前选中的整行数据,并对这个数据进行遍历,获取所有选中数据的id,存放在实例对象的数组中,请求后端携带这个id数组

后端逻辑

后端通过List集合接收到前端传递的json数组 ,对集合遍历删除

2、数据编辑实现表格数据回显

对当前行数据进行深拷贝即可获得回显数据

3、实现表格中动态显示不同数据的图片信息

四、图片上传功能

前端逻辑

使用elementUI中的上传标签,将当期选中的图片上传到服务器中,并通过方法接收返回的图片地址对象。

  1. action 图片提交地址
  2. :on-exceed="handleExceed"  图片上传超过限制的提示
  3. :auto-upload="false"  设置手动提交
  4. :before-upload    图片上传前的方法,对图片格式校验
  5. :on-success="handleAvatarSuccess"  图片上传成功的方法

//图片上传
			beforeAvatarUpload(file) {
				const isJPG = file.type === 'image/jpeg';
				const isPNG = file.type === 'image/png';
				const isLt2M = file.size / 1024 / 1024 < 2;
			
				if (!isJPG && !isPNG) {
					this.$message.error('上传头像图片只能是 JPG或者PNG 格式!');
				}
				if (!isLt2M) {
					this.$message.error('上传头像图片大小不能超过 2MB!');
				}
				return (isJPG || isPNG) && isLt2M;
			},
			handleAvatarSuccess(res, file) {
				// 上传图片成功后返回图片地址
				this.imgUrl = res.data
			},
			handleExceed() {
				this.$message.warning(`当前限制只能选择 1 张图片!`);
			},
			upload() {
				//手动提交
				this.$refs.upload.submit();
			},

后端逻辑

在七牛云配置好存储空间,保留accessKey 账号,后端引入七牛云工具类,并调用上传方法baseUpload(),返回图片地址

@Component
public class QiniuUtils {

    public static  final String url = "http://cdn.zxlsc.top/";

    //配置文件中写的accessKey账号
    @Value("${qiniu.accessKey}")
    private  String accessKey;
    @Value("${qiniu.accessSecretKey}")
    private  String accessSecretKey;

    public  boolean upload(MultipartFile file,String fileName){

        //构造一个带指定 Region 对象的配置类
        Configuration cfg = new Configuration(Region.huabei());
        //...其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);
        //...生成上传凭证,然后准备上传
        String bucket = "myblogssr";
        //默认不指定key的情况下,以文件内容的hash值作为文件名
        try {
            byte[] uploadBytes = file.getBytes();
            Auth auth = Auth.create(accessKey, accessSecretKey);
            String upToken = auth.uploadToken(bucket);
            Response response = uploadManager.put(uploadBytes, fileName, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = JSON.parseObject(response.bodyString(), DefaultPutRet.class);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }



    //防止冗余 直接写在工具类  Controller中调用
    public Result baseUpload(MultipartFile file, String path){
        //获取到文件名称 如a.jpg
        String originalFilename = file.getOriginalFilename();
        //唯一的文件名称
        String fileName = path + UUID.randomUUID().toString() + "." + StringUtils.substringAfterLast(originalFilename,".");
        //上传文件到哪呢? 上传到七牛云 将图片发放到离用户最近的服务器上,降低自身服务器的带宽消耗

        boolean upload = upload(file, fileName);
        if (upload){
            return Result.success(QiniuUtils.url + fileName);
        }
        return Result.fail(20001,"上传失败");
    }
}

五、在Vue中封装axios请求

1、在src中创建utils目录 创建request.js

在request中对axios进行二次封装,直接粘贴即可

//对axios二次封装
import axios from 'axios'

//对封装的axios方法起个名字
const request = axios.create({
	//通用请求地址前缀
	baseURL:'http://localhost:8989/api',
	//请求的超时时间
	timeout: 10000, 
})

//添加请求拦截器
request.interceptors.request.use(function (config){
	//在请求之前做什么
	return config;
},function(error){
	//对错误做点什么
	return Promise.reject(error);
});

//添加响应拦截器
request.interceptors.response.use(function (response){
	//对响应数据做点什么
	return response;
},function (error){
	//对响应错误做点什么
	return Promise.reject(error);
});

//将这个常量暴露
export default request

2、在src下再创建不同接口请求的js文件

//从request中引入
import request from "../utils/request.js"

//将请求方法暴露

//获取所有文章列表
export function getArticle(data){
	return request({
		method:"post",
		url:"/articles/list",
		data:data
	})
}

//获取文章总数
export function getCount(){
	return request({
		method:"get",
		url:"/article"
	})
}

3、在src下再创建一个index.js

此文件负责将所有的接口文件统一暴露出去直接使用

//按格式引入
import * as article from './article.js'
import * as user from'./user.js'
import * as tag from './tag.js'
import * as log from './log.js'

//负责将写好的请求暴露出去使用
export default {
	article,
	user,
	tag,
	log,
}

4、在main.js中引入这个api中的index.js

给暴露出去的方法设置全局属性 使得方法能够在全局调用

import api from './api/index.js'

//给这个api中的index起别名 后序调用直接使用this.$api
Vue.prototype.$api = api

5、调用方式

//原本使用axios方式
axios({
    method:"post",
    url:"http://localhost:8989/api/user"
    data:data
}).then(res => {
    //返回值
})


//使用封装的axios
//使用user.js中的getUser()请求
this.$api.user.getUser().then(res => {})

六、Echarts的基本引入

1、在Vue中导入Echarts

  1. 使用npm安装 echarts    npm i echarts
  2. 在vue文件中导入echarts 
  3. 在需要的标签内容设置 ref ---- vue提供的获取dom节点的方式
  4. 配置图形对象  
  5. 将图形对象暴露出去
官网提供的Demo  描述了图形的基本属性设置
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
      // 基于准备好的dom,初始化echarts实例
      var myChart = echarts.init(document.getElementById('main'));

      // 指定图表的配置项和数据
      var option = {
        title: {
          text: 'ECharts 入门示例'
        },
        tooltip: {},

        legend: {
          data: ['销量']
        },
        xAxis: {
          data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
        },
        yAxis: {},
        series: [
        //当有多条数据时使用遍历的方式设置series属性
          {
            name: '销量',
            type: 'bar',
            data: [5, 20, 36, 10, 10, 20]
          }
        ]
      };

      // 使用刚指定的配置项和数据显示图表。
      myChart.setOption(option);
    </script>

 2、不同图形的属性

折线:  series->type: "line"

柱状图: series->type: "bar"

柱状图与折线图只有type不同其他相同

 

饼状图:series->type: "pie"  radius:"50%"  其中对于饼状图不需要设置x,y轴  他也可以设置其他属性

 

3、补充  Echarts取数据

对于Echarts的使用难点在于如何对后端返回的数据进行筛选,将不同的数据提取出来对图形图像进行设置,只要将数据取出并赋值就可以完成Echarts的使用

所以在这里提供几个取数据的方法

数据类型  let obj = {"www":23,"ww":78}

数据类型为Array可以直接通过[0]的方式  通过索引位置获取

1、在js对象中获取所有的key值

Object.keys(obj)

2、在js对象中获取所有的value值

Object.values(obj)

3、将js对象转为集合类型使其能够通过索引取数据

Object.entries(obj2)

 

七、使用SpringBoot的拦截器拦截特定url

使用SpringBoot拦截器将特定url请求拦截 实现一个简单的 记录网站访问次数的功能,

1、创建Iterceptor

@Component
@SuppressWarnings({"all"})
public class URLInterceptor implements HandlerInterceptor {


/**
     * 请求前置处理(后置处理同理)
     *
     * @param request
     * @param response
     * @param handler
     * @return boolean
     */

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {
       //获取前端请求的接口地址
         String path = request.getServletPath();

        //对特定的接口进行设置
        if ("/articles/list".equals(path)) {
            //后置处理
            //对访问这个路径后执行的操作

        }
    }

2、在WebMvc中注入并添加

@Configuration
public class WebMVCConfig implements WebMvcConfigurer {

    //注入
    @Autowired
    private URLInterceptor urlInterceptor;

    //重写方法  将拦截器注入
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(urlInterceptor);
    }
}

八、实现账户退出并清空token

注意退出登录并清空token后应该返回登录页面

1、在main.js中添加导航路由守卫

当不存在token时会立马跳转到登录页

//添加路由守卫
router.beforeEach((to,from,next) => {
	//判断token是否存在 从Cookie读取
	const token = Cookie.get('token')
	if(!token && to.name !== 'login'){
		//token不存在 说明当前用户未登录 应该跳转未登录页面
        //name 是路由配置中指定路由的名称
		next({ name: 'login' })
	}else if(token && to.name === 'login'){
		//token存在 说明登录 此时跳转首页
		// next({ name:from.name })
		next({ name:'home' })
	}else{
		next()
	}
})

2、退出逻辑

logout() {
	// 清空token
	Cookie.set('token', '')
	// 跳转到登录页  防止路由守卫不生效
	this.$router.push({
		path: '/login'
	})
	this.$message({
		type: 'success',
		message: '退出成功!'
	});
},

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

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

相关文章

ThinkPHP 之 SQLI审计分析(二)

说明 该文章来源于同事lu2ker转载至此处&#xff0c;更多文章可参考&#xff1a;https://github.com/lu2ker/ 文章目录说明0x00 测试代码做了什么&#xff1f;0x01 分析调用0x02 漏洞点的发现、构造、利用0x03 总结Time&#xff1a;9-3影响版本&#xff1a;ThinkPHP5.0.10 Pa…

详细介绍chrony服务器

chrony服务器 硬件时间&#xff1a;BIOS里面&#xff1b;关机后依然运行&#xff0c;主板电池为它供电&#xff1b;RTC时钟 系统时间&#xff1a;开机后&#xff0c;软件启动读取硬件时钟&#xff0c;之后独立运行 Chrony 的配置文件是/etc/chrony.conf chronyd服务器端 ch…

【目标检测】Mask rcnn代码实现Pytorch版,适用30系列显卡!(测试版)

目录&#xff1a;Mask rcnn代码实现Pytorch版一、环境二、mmdetection环境搭建三、测试四、结果展示为什么选择使用Pytorch版本&#xff1f;因为本人换电脑了&#xff0c;显卡升级为30系列&#xff0c;而30系列显卡的 CUDA 版本要求是 11.x。一、环境 cudatoolkit …

MYSQL之两阶段提交和组提交(数据一致性)

我们在MySQL 的日志中详细的介绍了undo log、redo log、binlog这三个日志和所用到的一些缓存知识&#xff0c;那么下面我们分析一下更新语句执行过程&#xff0c;它们是怎么变化的呢&#xff1f;下面我们直接给答案吧。假如我们修改一行主键索引&#xff08;id&#xff09;为1的…

电力系统激励型需求响应+自适应多群体优化算法(Python实现)

目录 ​编辑 0 前言 1 激励型DR和价格型DR 2 激励型DR模型 3 Python代码实现 4 自适应多群体优化算法&#xff08;AMPO&#xff09; 5 Python代码实现 0 前言 风、光等清洁能源因具有环保、资源丰富等优点而受到电力行业的重视,电力行业开始大力发展清洁能源发电。同时…

MySQL详解,库和表的基础操作

目录 前言 一、预备知识 1、服务器&#xff0c;数据库&#xff0c;表关系 2、SQL分类 3、连接服务器 二、库的操作 1、创建数据库 2、查看字符集和校验规则 2.1 查看系统默认字符集以及校验规则 2.2 查看数据库支持的字符集和字符集校验规则 3、操纵数据库 3.1查看…

ros tf坐标

参考&#xff1a; 讲解&#xff1a;https://www.bilibili.com/video/BV1zt411G7Vn/?p18&vd_source3a1ad336af3eaae4fcced56c75d309d1ROS程序&#xff1a;https://gitee.com/guyuehome/ros_21_tutorials/tree/master/learning_tfROS2程序&#xff1a;https://gitee.com/gu…

公司企业兔年祝福元旦祝福贺卡邀请函模板!

能群发的贺卡邀请函如何制作&#xff1f;想制作一个专属的祝福贺卡邀请函有什么方法&#xff1f;下面跟着小编的乔拓云工具教程&#xff01;教你如何使用这个工具在线就能轻松搞定设计需求&#xff0c;不仅有海量模板供你使用&#xff0c;还能一键生成链接轻松转发&#xff01;…

利用vue-cli创建vue3工程

需注意&#xff1a;想创建vue3工程&#xff0c;对vue-cli版本有要求&#xff0c;必须确保vue-cli在4.5.0以上 目录 1、查看vue-cli版本 2、创建工程 3、启动 1、查看vue-cli版本 vue --version&#xff08;小写v&#xff09; vue --version或者 vue -V&#xff08;大写v&…

深入分析Java中finalize方法的作用和底层原理

finalize方法是什么 finalize方法是Object的protected方法&#xff0c;Object的子类们可以覆盖该方法以实现资源清理工作&#xff0c;GC在首次回收对象之前调用该方法。 finalize方法与C的析构函数的区别 finalize方法与C中的析构函数不是对应的&#xff0c;C中的析构函数调…

(小程序)后台交互-首页

目录 一、小程序首页动态数据加载 1.数据库准备 2.后台准备 ① pom.xml ② 配置数据源 ③ 整合mybatis ④ 代码生成 ⑤ mybatis-generator 二、准备前端的首页的数据 1、Promise 2.封装request 3.会议展示 三、通过wxs将首页动态数据优化 一、小程序首页动态数据加…

Git命令版(powernode)

Git命令版&#xff08;powernode&#xff09; 目录Git命令版&#xff08;powernode&#xff09;1.添加文件相关命令案例实操小结&#xff1a;2.工作区和暂存区2.1 名词解释。2.1.1 工作区&#xff08;Working Directory&#xff09;2.1.2 版本库&#xff08;Repository&#xf…

数据结构之双向链表

双向链表与单向链表较为类似&#xff0c;单向链表有一个指针域&#xff0c;用来指向后继结点&#xff0c;而双向链表有两个指针域&#xff0c;分别用来指向前驱结点和后继结点。玩双向链表时一定要从单向链表的思维中跳出来&#xff0c;否则在操作双向链表时就会出现各种问题。…

【Python百日进阶-数据分析】Day144 - plotly箱线图:go.box()实例

文章目录4.2 go.Box 箱线图4.2.1 基本箱线图4.2.2 基本水平箱线图4.2.3 显示基础数据的箱线图4.2.4 修改计算四分位数的算法4.2.5 带有预先计算的四分位数的箱线图4.2.6 彩色箱线图4.2.7 箱线图样式均值和标准差4.2.8 造型异常值4.2.9 分组箱线图4.2.10 分组水平箱线图4.2.11 彩…

一起学习用Verilog在FPGA上实现CNN----(四)池化层设计

1 池化层设计 自顶而下分析池化层的设计过程 1.1 Average Pool Multi Layer 图为该项目的平均池化层&#xff0c;其包含一个AvgPoolSingle单元&#xff0c;模块的输入为图像特征矩阵&#xff0c;输出为池化后的特征矩阵 图片来自附带的技术文档《Hardware Documentation》 …

Java开发学习(三十六)----SpringBoot三种配置文件解析

一、 配置文件格式 我们现在启动服务器默认的端口号是 8080&#xff0c;访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80&#xff0c;这样在访问的时候就可以不写端口号了&#xff0c;如下 http://localhost/books/1 而 SpringB…

电脑屏录软件,这3款良心软件,分享给你

现在很多人会使用电脑屏录软件&#xff0c;有些用来记录游戏中的精彩操作&#xff0c;有些用来记录在线教学课程&#xff0c;有些用来记录在线视频会议。现在有各种各样的电脑屏录软件。选择一个好的电脑屏录软件是非常重要的。电脑屏录软件哪个好&#xff1f;下面小编分享3款良…

前端基础(四)_数据类型的强制转换

数据类型的强制转换就是通过js提供的函数进行数据转换。常见的就是将其他类型的数据转换成number类型和string类型。 一、其他类型转 number 类型 1.Number Number 方法将其他类型的数据转换为Number类型&#xff0c;返回一个新的数值&#xff0c;不会改变变量本身。 例1&…

【Linux】Linux编辑器-vim的使用以及指令集

推荐先将vim配置好后再使用会方便一些&#xff0c;就是将Linux下vim打造成C IDE的样子。自动配置vim vim1.vim的基本概念2.vim的基本操作2.1进入vim编辑界面2.2 如何在vim编辑代码2.3 退出vim并保存代码2.4一张图总结基本操作3.vim正常模式命令集3.1 进入插入模式和退出插入模式…

自己电脑中安装黑群辉NAS

前期准备&#xff1a;一个品牌U盘(制作后就是启动盘需一直插电脑上)、一台安装群辉的电脑&#xff08;可以没有硬盘&#xff09;、一台可正常开机的电脑 资源下载&#xff1a; 百度网盘链接&#xff1a;链接: https://pan.baidu.com/s/1t_yVON16Pt8H1ytpvf0J-A?pwdxe7m 提取…