手把手教你写代码——基于控制台的通讯录管理系统(多人)(代码详细注释)

news2024/11/24 3:16:17

写在前面

本文章适合刚开始学习java的同学,不适合已参与java开发的人群!本项目源代码已绑定资源中可免费获取!如果对你有帮助请

栏目介绍

本栏目专为入门java学习者设计的一些简单的入门项目

功能介绍

本项目为简单的基于控制台的通讯录管理系统,所需要的环境仅仅为jdk以及mysql(版本不限)!只有一个简单的eclipse软件以及我们的mysql可视化工具(视频使用navicat)

本项目数据库表有二个,本项目是之前的单表项目的升级版本
本项目使用mvc设计模式,使用面向对象的开发思想
本项目使用最基础的jdbc的方式链接的数据库

本项目主要实现的功能有:

  • 注册登录
  • 系统运行成功后的欢迎及菜单页面
  • 按照登录人添加联系人功能
  • 按照登录人进行联系人查询功能(分名称和手机号查询)
  • 按照登录人显示联系人列表
  • 按照登录人根据编号删除指定编号的联系人
  • 按照登录人修改指定编号的联系人
  • 退出登录

业务点处理:

当前登录人操作只能操作自己的数据,用户登录成功后,显示的列表只能显示自己录入的数据!
注册:用户表按照的是用户名作为唯一标识,也就是不能注册重复的用户名
新增:对于不同用户来说通讯录的no是可以重复的,但是对于同一个用户来说录入的通讯通好友的编号no是不允许重复的
修改:用户修改也是通过编号以及自己的登录状态来修改自己的数据
删除:用户删除输入的编号也是只针对自己的数据

项目实现截图

项目结构:
在这里插入图片描述

数据表结构

1.登录用户表
在这里插入图片描述
2.用户的通讯录数据表
在这里插入图片描述

页面截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

项目功能及代码

1.JDBC数据库连接工具类:

package com.maker.address.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 数据库连接工具类
 * @author Administrator
 *
 */
public class DBUtil {
    
    public static String db_url = "jdbc:mysql://localhost:3306/addressbook?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=utf-8";
    public static String db_user = "root";
    public static String db_pass = "123456";
    
    public static Connection getConn () {
        Connection conn = null;
        
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(db_url, db_user, db_pass);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return conn;
    }
    
    /**
     * 关闭链接
     * @param state
     * @param conn
     */
    public static void close (Statement state, Connection conn) {
        if (state != null) {
            try {
                state.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 关闭链接
     * @param state
     * @param conn
     */
    public static void close (ResultSet rs, Statement state, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
        if (state != null) {
            try {
                state.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

2.运行程序的主类:UserMain

主类中包含各种页面显示以及主方法入口

package com.maker.address.web;

import java.util.ArrayList;
import java.util.Scanner;

import com.maker.address.entity.Login;
import com.maker.address.entity.User;
import com.maker.address.service.LoginService;
import com.maker.address.service.UserService;


//主类  程序从这里的main方法开始
public class UserMain {
	//静态的user服务层对象
	static UserService user = new UserService();
	//静态的用户登录服务层对象
	static LoginService loginService = new LoginService();
	//静态的全局的用户输入对象
	static Scanner sc = new Scanner(System.in);
	//登录对象保存
	static Login LOGIN = null;
	
	/**
	 * main方法执行后先执行start方法
	 * 这里就是对登录注册的页面显示的操作
	 */
	public static void start(){
		System.out.println("=======请选择=====");
		System.out.println("【1】注册");
		System.out.println("【2】登录");
		int index = sc.nextInt();
		//根据用户输入的操作来进行下一步的指令
		//每一个指令之后都是重新进行start方法,只有在登录成功的时候,登录方法内部进入了into这个方法,就是进入系统中了
		switch(index){
		case 1:
			//注册
			toRegist();
			start();
			break;
		case 2:
			//登录
			login();
			start();
			break;
			default:
				System.out.println("请输入正确的指令!");
				start();
				break;
		}
	}

	//登录方法
	private static void login() {
		// TODO Auto-generated method stub
		System.out.println("请输入用户名:");
		String username = sc.next();
		System.out.println("请输入密码:");
		String password = sc.next();
		//根据输入的用户名密码来调用服务层接口
		LOGIN = loginService.toLogin(username, password);
		if(LOGIN!=null){
			//登录成功的时候会返回数据库中的登录对象,然后将对象赋值给全局的登录对象,这样在做其他操作的时候直接使用就行
			//登录成功后进入系统中
			into();
		}
	}

	//注册的方法
	private static void toRegist() {
		// TODO Auto-generated method stub
		System.out.println("请输入用户名:");
		String username = sc.next();
		System.out.println("请输入密码:");
		String password = sc.next();
		System.out.println("请确认密码:");
		String rePassword = sc.next();
		//根据用户输入的用户名密码来进行校验
		if(password.equals(rePassword)){
			//注册成功不做其他操作,在start方法中会重新执行start
			loginService.toRegist(username, rePassword);
		}else{
			System.out.println("二次密码输入不一致!");
		}
	}
		
	/**
	 * 这里就是用户登录成功后进入系统的页面显示方法
	 */
	public static void into() {
		System.out.println("=======通讯录管理系统=====");
		System.out.println("【1】添加联系人");
		System.out.println("【2】联系人查询");
		System.out.println("【3】显示联系人列表");
		System.out.println("【4】根据编号删除指定编号的联系人");
		System.out.println("【5】修改指定编号的联系人");
		System.out.println("【0】退出");
		System.out.println("=============================");
		int i = sc.nextInt();
		//接收用户输入的指令来进行不同的操作
		switch (i) {
		case 1:
			//添加联系人
			add();
			into();
			break;
		case 2:
			//联系人查询
			System.out.println("【1】通过联系人姓名查询/【2】通过联系人电话查询");
			int a = sc.nextInt();
			findbyName(a);
			into();
			break;
		case 3:
			//显示联系人列表
			show();
			into();
			break;
		case 4:
			//根据编号删除指定编号的联系人
			del();
			into();
			break;
		case 5:
			//修改指定编号的联系人
			update();
			into();
			break;
		case 0:
			//退出
			System.out.println("谢谢使用,再见!");
			System.exit(0);
			break;
		default:
			//不存在的指令
			System.out.println("请输入正确的指令!");
			into();
			break;
		}
	}

	/**
	 * 修改用户的方法
	 * 1.接收用户输入的联系人编号以及修改的数据
	 * 2.然后中间进行手机号验证以及邮箱验证
	 * 3.最后调用服务层updateUser方法去执行修改操作
	 */
	private static void update() {
		// TODO Auto-generated method stub
		System.out.println("请输入要修改的联系人编号:");
		int a = sc.nextInt();
		System.out.println("请输入姓名:");
		String b = sc.next();
		System.out.println("请输入手机号:");
		String c = sc.next();
		judgePhone(c);
		System.out.println("请输入QQ:");
		String d = sc.next();
		System.out.println("请输入邮箱地址:");
		String e = sc.next();
		judgeEmail(e);
		User x = new User(a, b, c, d, e,LOGIN.getId());
		if (user.updateUser(x)) {
			System.out.println("修改成功!");
		}
	}

	/**
	 * 新增方法
	 * 1.接收用户输入的相关信息
	 * 2.中间进行手机号验证以及邮箱验证
	 * 3.调用服务器addUser新增接口
	 */
	public static void add() {
		System.out.println("请输入联系人编号:");
		int a = sc.nextInt();
		System.out.println("请输入联系人姓名:");
		String b = sc.next();
		System.out.println("请输入联系人手机号:");
		String c = sc.next();
		judgePhone(c);
		System.out.println("请输入联系人QQ:");
		String d = sc.next();
		System.out.println("请输入联系人邮箱地址:");
		String e = sc.next();
		judgeEmail(e);
		User x = new User(a, b, c, d, e,LOGIN.getId());
		if (user.addUser(x)) {
			System.out.println("添加成功!");
		}
	}

	/**
	 * 校验手机号  
	 * 规则:11位  数字1开头  第二位为34589 后面9位1-9任意
	 * 
	 * 校验不通过后可以重新输入
	 * @param phone 手机号
	 */
	public static void judgePhone(String phone) {

		if (phone.matches("1[34589][0-9]{9}")) {

		} else {
			System.out.println("手机号输入有误,请重新输入");
			String v = sc.next();
			judgePhone(v);
		}
	}
	/**
	 * 校验邮箱
	 * 规则:不包括特殊字符  中间有@
	 * 
	 * 校验不通过后可以重新输入
	 * @param email 邮箱
	 */
	public static void judgeEmail(String email) {

		if (email.matches("[A-Za-z0-9]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)")) {

		} else {
			System.out.println("邮箱格式输入有误,请重新输入");
			String v = sc.next();
			judgeEmail(v);
		}
	}

	/**
	 * 查询联系人方法
	 * 
	 * 查询方法调用user服务层接口然后参数加上当前登录人的id
	 * 
	 * @param a  输入的指令  1按照姓名  2按照电话
	 */
	public static void findbyName(int a) {
		if (a == 1) {
			System.out.println("请输入联系人姓名");
		} else {
			System.out.println("请输入联系人电话");
		}
		String name = sc.next();
		User user = UserMain.user.searchByName(name,LOGIN.getId());
		System.out.println(user);
	}

	/**
	 * 显示所有联系人的方法
	 * 调用user服务层接口根据当前登录人的id查询
	 */
	public static void show() {
		ArrayList list = user.showInfo(LOGIN.getId());
		for (Object o : list) {
			System.out.println(o);
		}
	}

	/**
	 * 删除方法
	 * 1.根据用户输入的要删除的联系人编号
	 * 2.调用user服务器接口根据当前登录人id以及要删除的联系人编号进行删除
	 */
	public static void del() {
		System.out.println("请输入编号");
		int no = sc.nextInt();
		if (user.delUser(no,LOGIN.getId())) {
			System.out.println("删除成功");
		}
	}

	//运行程序的主方法,右键运行后会执行start方法
	public static void main(String[] args) {
		start();
	}
}

  1. user的服务层代码 UserService
package com.maker.address.service;

import java.util.ArrayList;
import java.util.Objects;

import com.maker.address.dao.UserDao;
import com.maker.address.entity.User;

/**
 * 用户服务层
 * @author Administrator
 *
 */
public class UserService {
	 	UserDao ud = new UserDao();
	 
	 	//新增用户
	    public boolean addUser(User user){
	    	//判断编号是否存在,存在的话将不允许新增
	    	User record = ud.queryByNo(user.getNo(),user.getUserId());
	    	if(record!=null){
	    		System.out.println("编号已存在!");
	    		return false;
	    	}
	        return ud.add(user);
	    }
	 
	    /**
	     * 公共的查询所有数据的方法
	     * 查询出当前登录人的所有的联系人
	     * @param userId 当前登录人id
	     * @return
	     */
	    public ArrayList showInfo(Integer userId){
	        return ud.getAll(userId);
	    }
	    
	    /**
	     * 通过名称或者电话查询联系人
	     * 1.通过showInfo查询当前登录人的所有联系人
	     * 2.通过字段进行过滤查询出符合的联系人
	     * 
	     * @param name 用户输入的
	     * @param userId 当前登录人的id
	     * @return
	     */
	    public User searchByName(String name,Integer userId){
	    	ArrayList<User> s = showInfo(userId);
	        for (User user : s) {
	            if (Objects.equals(name,user.getName()) ||Objects.equals(name,user.getPhone())){
	                return user;
	            }
	        }
	        return null;
	    }
	 
	    /**
	     * 修改方法
	     * @param user 要修改的实体
	     * @return 
	     */
	    public boolean updateUser(User user){
	    	boolean num = ud.updateUser(user);
	        if(!num) {
	            System.out.println("该用户不存在");
	            return false;
	        }
	        return true;
	    }
	 
	    /**
	     * 删除联系人的方法
	     * 1.通过showInfo查询当前登录人的所有联系人
	     * 2.过滤查询要删除的联系人的编号
	     * 3.执行删除
	     * @param no  要删除人的编号
	     * @param userid 当前登录人id
	     * @return
	     */
	    public boolean delUser(int no,Integer userid){
	    	ArrayList<User> s = showInfo(userid);
	        User user = null;
	        for(User u:s) {
	            if(no == u.getNo()) {
	                user = u;
	                break;
	            }
	        }
	        if(user == null) {
	            System.out.println("该用户不存在");
	            return false;
	        }
	        return ud.remove(user);
	    }
}

4.user的Dao层代码 UserDao

package com.maker.address.dao;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import com.maker.address.entity.User;
import com.maker.address.util.DBUtil;

/**
 * dao层处理对数据库的操作
 * @author Administrator
 *
 */
public class UserDao {

	//新增用户
	public boolean add(User user) {
		// TODO Auto-generated method stub
		String sql = "insert into user(no,name,phone,qq,email,userid) values ("+user.getNo()+",'"+user.getName()+"','"+user.getPhone()+"','"+user.getQQ()+"','"+user.getEmail()+"',"+user.getUserId()+")";
		Connection conn = DBUtil.getConn();
		Statement state = null;
		int num = 0;
		System.out.println(sql);
		try {
			state = conn.createStatement();
			num = state.executeUpdate(sql);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			DBUtil.close(state, conn);
		}
		return num > 0;
	}

	//查询所有用户
	public ArrayList getAll(Integer userid) {
		// TODO Auto-generated method stub
		String sql = "select * from user where userid =" + userid;
		Connection conn = DBUtil.getConn();
		Statement state = null;
		ArrayList<User> list = new ArrayList<>();
		ResultSet rs = null;
		try {
			state = conn.createStatement();
			rs = state.executeQuery(sql);
			while(rs.next()){
				//结果集中有数据  代表查询出来有数据
				//创建user对象,将数据存入到对象集合中
				User user = new User();
				user.setNo(rs.getInt("no"));
				user.setName(rs.getString("name"));
				user.setPhone(rs.getString("phone"));
				user.setQQ(rs.getString("qq"));
				user.setEmail(rs.getString("email"));
				user.setUserId(rs.getInt("userid"));
				list.add(user);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			DBUtil.close(rs,state, conn);
		}
		return list;
	}

	//按照编号查询用户
	public User queryByNo(int no,Integer userid) {
		// TODO Auto-generated method stub
		String sql = "select * from user where no="+no + " and userid="+userid;
		Connection conn = DBUtil.getConn();
		Statement state = null;
		User user = null;
		ResultSet rs = null;
		try {
			state = conn.createStatement();
			rs = state.executeQuery(sql);
			while(rs.next()){
				user = new User();
				//结果集中有数据  代表查询出来有数据
				//创建user对象,将数据存入到对象集合中
				user.setNo(rs.getInt("no"));
				user.setName(rs.getString("name"));
				user.setPhone(rs.getString("phone"));
				user.setQQ(rs.getString("qq"));
				user.setEmail(rs.getString("email"));
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			DBUtil.close(rs,state, conn);
		}
		return user;
	}

	//删除用户按照编号
	public boolean remove(User user) {
		// TODO Auto-generated method stub
		String sql = "delete from user where no = '"+user.getNo()+"' and userid="+user.getUserId();
		Connection conn = DBUtil.getConn();
		Statement state = null;
		int num = 0;
		try {
			state = conn.createStatement();
			num = state.executeUpdate(sql);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			DBUtil.close(state, conn);
		}
		return num > 0;
	}

	//修改用户按照编号修改
	public boolean updateUser(User user) {
		// TODO Auto-generated method stub
		String sql = "update user set name='"+user.getName()+"',phone='"+user.getPhone()+"',qq='"+user.getQQ()+"',email='"+user.getEmail()+"' where no = "+user.getNo();
		
		Connection conn = DBUtil.getConn();
		Statement state = null;
		int num = 0;
		try {
			state = conn.createStatement();
			num = state.executeUpdate(sql);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			DBUtil.close(state, conn);
		}
		return num > 0;
	}
}

这里贴出的是关于User的一系列操作类,如果需要所有源代码的可以直接免费下载去!!

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

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

相关文章

音乐节《迷笛音乐节》游玩感

上周&#xff0c;去了烟台&#xff0c;参加音乐节&#xff0c;以前从未参加过&#xff0c;所以趁着本周六周日双休的时候&#xff0c;去游玩了一次。&#xff08;1&#xff09;一种新奇体验 对于自己来说&#xff0c;参加音乐节还是一种新奇的体验的&#xff0c;也是疫情放开了…

【MyBatis】初学MyBatis

目录 MyBatis 是什么&#xff1f;MyBatis框架搭建1.添加MyBatis框架2.设置MyBatis配置数据库的相关链接信息xml 保存路径和命名格式 根据MyBatis写法完成数据库的操作MyBatis插件MyBatis传递参数查询${} 和 #{} 有什么区别&#xff1f;SQL注入问题 MyBatis like查询MyBatis多表…

Lombok,一个神奇的存在

1、概述 Lombok主要用于在编译POJO类源文件时通过注解的方式自动为该类生成构造方法、getter/setter、equals、hashcode、toString等方法&#xff0c;有效地简化了POJO类代码&#xff0c;提高了软件的开发速度。 2、安装 a、启动IntelliJ IDEA—>点击CtrlAltS快捷键&…

【LeetCode】链表反转

题目 题目&#xff1a;给定单链表头节点&#xff0c;将单链表的链接顺序反转过来 例&#xff1a; 输入&#xff1a;1->2->3->4->5 输出&#xff1a;5->4->3->2->1 要求&#xff1a;按照两种方式实现 解决办法 方式一&#xff1a;&#xff08;直接迭…

从0开始自学网络安全(黑客)

前言 黑客技能是一项非常复杂和专业的技能&#xff0c;需要广泛的计算机知识和网络安全知识。你可以参考下面一些学习步骤&#xff0c;系统自学网络安全。 在学习之前&#xff0c;要给自己定一个目标或者思考一下要达到一个什么样的水平&#xff0c;是学完找工作&#xff08;…

这所211考数一英二,学硕降分33分,十分罕见!

一、学校及专业介绍 合肥工业大学&#xff08;Hefei University of Technology&#xff09;&#xff0c;简称“合工大”&#xff0c;校本部位于安徽省合肥市&#xff0c;是中华人民共和国教育部直属的全国重点大学&#xff0c;是国家“双一流”建设高校&#xff0c; 国家“211工…

PHP代码审计——实操!

ctfshow PHP特性 web93 八进制与小数点 <?php include("flag.php"); highlight_file(__FILE__); if(isset($_GET[num])){$num $_GET[num];if($num4476){die("no no no!");}if(preg_match("/[a-z]/i", $num)){die("no no no!")…

git 忽略掉不需要的文件

第一步&#xff1a;创建.gitignore文件 touch .gitignore 第二步&#xff1a;使用vi编辑器 输入不需要的文件&#xff0c;或用通配符*来忽视一系列文件 效果&#xff1a;

【Java可执行命令】(十二)依赖分析工具jdeps:通过静态分析字节码并提取相关信息来实现依赖分析 ~

Java可执行命令之jdeps 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 语法格式3.2 jdeps -dotoutput < dir>3.3 jdeps -s3.4 jdeps -v3.5 jdeps -cp < path>3.6 注意事项&#xff1a; 4️⃣ 应用场景&#x1f33e; 总结 1️⃣ 概念 Java中的jdeps命令是一个用于分析类…

使用脱机 MFA确保远程员工的安全

远程工作支持的优势 未更改的企业访问&#xff1a;远程工作支持开辟了访问企业网络和资源以及其中保存的数据的替代方法。应采取必要措施&#xff0c;确保它们保持完整&#xff0c;不受远程破坏企图的影响。提高工作效率&#xff1a;理想情况下&#xff0c;远程工作支持可提高…

程序框架-事件中心模块-观察者模式

1.Monster //触发事件 EventCenter.GetInstance().EventTrigger("MonsterDead",this);2.Player void Start() { EventCenter.GetInstance().AddEventListener("MonsterDead", MonsterDeadDo); }public void MonsterDeadDo(object info) {Debug.Log(&q…

【测试开发】Mq消息重复如何测试?

本篇文章主要讲述重复消费的原因&#xff0c;以及如何去测试这个场景&#xff0c;最后也会告诉大家&#xff0c;目前互联网项目关于如何避免重复消费的解决方案。 Mq为什么会有重复消费的问题? Mq 常见的缺点之一就是消息重复消费问题&#xff0c;产生这种问题的原因是什么呢…

从封面开始,打造一个引人注目的视频作品

在如今的互联网时代&#xff0c;短视频已经成为了人们生活中不可或缺的一部分。而一个吸引人的视频封面可以让你的作品更具吸引力&#xff0c;吸引更多观众的点击。那么&#xff0c;如何制作一个令人印象深刻的视频封面呢&#xff1f;下面就让我们揭秘一些实用技巧吧&#xff0…

Chrome 75不支持保存成mhtml的解决方法

在Chrome 75之前&#xff0c;可以设置chrome://flags -> save as mhtml来保存网页为mhtml。 升级新版&#xff0c;发现无法另存为/保存网页为MHTML了。 在网上搜索无果后&#xff0c;只得从chromium项目的commits中查找&#xff0c;原来chrome搞了个"Chrome Flag Owner…

新闻稿发布中,首发来源和转载是什么意思?

一秒推小编告诉您&#xff0c;在新闻稿发布中&#xff0c;首发来源和转载是两个常用的词语&#xff0c;它们有着不同的含义和使用场合。#新闻稿发布# 首发来源指的是原创的、第一次发布该条新闻的媒体或媒体机构。比如&#xff0c;如果一家新闻机构发布了一则新闻稿&#xff0c…

圆圈中最后剩下的数字(约瑟夫环)——剑指 Offer 62

文章目录 题目描述法一 数学递归 题目描述 法一 数学递归 int lastRemaining(int n, int m){return f(n, m);}int f(int n, int m){if(n1){return 0;}int x f(n-1, m);return (mx)%n;}

浅析视频技术与AI智能感知与生鲜供应链的数字化应用

一、行业背景 近年来&#xff0c;我国肉类、水果、蔬菜、水产品、乳品、速冻食品等生鲜市场需求快速增长&#xff0c;营商环境持续改善&#xff0c;推动冷链物流较快发展&#xff0c;但仍面临不少突出瓶颈和痛点难点卡点问题&#xff0c;难以有效满足市场需求。传统生鲜食材供…

【EI/SCOPUS征稿】2023年通信网络与机器学习国际学术会议(CNML 2023)

2023年通信网络与机器学习国际学术会议&#xff08;CNML 2023&#xff09; 2023 International Conference on Communication Networks and Machine Learning 随着数据流量的显著增长&#xff0c;新的通信应用程序不断出现&#xff0c;并产生更多的数据流量&#xff0c;这些数…

单片机外部晶振故障后自动切换内部晶振——以STM32为例

单片机外部晶振故障后自动切换内部晶振——以STM32为例 作者日期版本说明Dog Tao2023.08.02V1.0发布初始版本 文章目录 单片机外部晶振故障后自动切换内部晶振——以STM32为例背景外部晶振与内部振荡器STM32F103时钟系统STM32F407时钟系统 代码实现系统时钟设置流程时钟源检测…

RabbitMQ输出日志配置

参考地址rabbitmq启用日志功能记录消息队列收发情况_rabbitmq开启日志_普通网友的博客-CSDN博客 启用日志插件命令 # 设置用户权限 rabbitmqctl set_user_tags mqtt-user administrator rabbitmqctl set_permissions -p / mqtt-user ".*" ".*" ".*&…