JavaSE+JDBC进行控制台输出的客户管理系统! (实训/课堂实践推荐)

news2024/11/15 21:55:02

本人博客:玖玖的个人博客 (zhangxi.online),欢迎大家来踩

该文章原地址:

JavaSE+JDBC进行控制台输出的客户管理系统! (实训/课堂实践推荐) (zhangxi.online)

本人诚挚的特别感谢:尚硅谷/黑马程序员提供的学习案例


项目介绍:

利用JavaSE技术,进行控制台输出的客户管理系统! 主要功能让包含客户展示,客户删除,客户添加,客户修改,退出系统!

实践前置要求:

  • JAVASE基础
  • MySQL基础
  • JDBC基础

项目地址:

Git:JDBC-CMS: 控制台输出的客户管理系统! 主要功能让包含客户展示,客户删除,客户添加,客户修改,退出系统!

如果不会克隆下载,没关系,下面会一步一步的慢慢引导各位搭建及敲一遍代码。

项目截图:

现在开始进入正题

一、回顾JDBC-API

API的基本使用步骤:1、注册驱动【依赖的jar包 进行安装】 ----> 2、获取连接【connection建立连接】 ----> 3、创建发送sql语句对象【statement 创建发送sql语句的statement】(小车) ----> 4、发送sql语句,并获取返回结果【statement发送sql语句到数据库 并且取得返回结构】 ----> 5、结果集解析【将result结果解析出来】 ----> 6、资源关闭【释放resultset、statement、connection】

其中我们可以称第4步statement为一个发车的过程,使用 statement.addBatch();还可以模拟小车装很多的货物(批量数据插入),最终使用statement.executeBatch();完成发车! 批量操作!

  1. 但这样会造成每次都通过DriverManager获取新连接,用完直接抛弃断开, 连接的利用率太低,太浪费。
  2. 对于数据库服务器来说,压力太大了。我们数据库服务器和Java程序对连接数也无法控制,很容易导致数据库服务器崩溃。

我们可以建立一个连接池,这个池中可以容纳一定数量的连接对象,一开始, 我们可以先替用户先创建好一些连接对象,等用户要拿连接对象时,就直接从池中拿,不用新建了,这样也可以节省时间。然后用户用完后,放回去,别人可以接着用。

可以提高连接的使用率。当池中的现有的连接都用完了,那么连接池可以向服务器申请新的连接放到池中。

JDBC 的数据库连接池使用 javax.sql.DataSource接口进行规范,所有的第三方连接池都实现此接口,自行添加具体实现!也就是说,所有连接池获取连接的和回收,其中Druid是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于一身的数据库连接池,妥妥国货之光!!!!

所以本案例使用的是Druid。

二、搭建项目

新建项目

虽说勾选到了Maven,但本项目暂未使用到Maven,可以忽略。

新建目录lib用于存放Jar包

1、引入两个Jar包
  • druid-1.1.21.jar
  • mysql-connector-java-8.0.27-bin.jar

推荐3种方式引入:

1、可从Git上扒我上面上传的包下来,复制到自己的项目中。

2、可以直接从Maven中直接下载。(需要Maven基础)

3、也可以从官网下载适合自己的版本。(百度就能找到)

2、创建dao、service、javabean、view、util包

  • dao-做数据交互,实现对数据库的操作(增、删、改、查)
  • service-服务层,专注于业务逻辑,对数据库的操作则需要借助 Dao 层实现
  • javabean-实体类
  • view-做视图界面
  • util-存放一堆工具类
3、添加数据库相关配置
-- 员工表

CREATE TABLE t_customer(
  id INT PRIMARY KEY AUTO_INCREMENT COMMENT '客户主键',
  NAME VARCHAR(20)  COMMENT '客户名称',
  gender VARCHAR(4) COMMENT '客户性别',
  age INT  COMMENT '客户年龄',
  salary DOUBLE(8,1) COMMENT '客户工资',
  phone VARCHAR(11) COMMENT '客户电话')

4、在resources添加druid.properties

# druid连接池需要的配置参数,key固定命名
driverClassName=com.mysql.cj.jdbc.Driver
username=root
password=root
url=jdbc:mysql:///zhangxi

三、创建工具类(在util包下)

1、创建JDBCTools

这个工具类的作用就是用来给所有的SQL操作提供“连接”,和释放连接。

创建变量DataSource与ThreadLocal
    private static DataSource ds;
    private static ThreadLocal<Connection> tl = new ThreadLocal<>();
  • 这里使用ThreadLocal的目的是为了让同一个线程,在多个地方getConnection得到的是同一个连接。
  • 这里使用DataSource的目的是为了(1)限制服务器的连接的上限(2)连接的重用性等
静态代码块
static {
        try {
            Properties properties = new Properties();
            properties.load(ClassLoader.getSystemResourceAsStream("druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
获取连接方法
    public static Connection getConnection() throws Exception{
        Connection connection = tl.get();
        if (connection ==null ){//当前线程还没有拿过连接,就给它从数据库连接池拿一个
            connection = ds.getConnection();
            tl.set(connection);
        }
        return connection;
    }
释放连接方法

  public static void free() throws Exception{
        Connection connection = tl.get();
        if (connection != null){
            tl.remove();
            connection.setAutoCommit(true);//避免还给数据库连接池的连接不是自动提交模式(建议)
            connection.close();
        }
    }

2、完整的JDBCTools代码

package com.zhangxi.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.Properties;

/**
 * ClassName: JDBCTools
 * Package: com.zhangxi
 */
/*
这个工具类的作用就是用来给所有的SQL操作提供“连接”,和释放连接。
这里使用ThreadLocal的目的是为了让同一个线程,在多个地方getConnection得到的是同一个连接。
这里使用DataSource的目的是为了(1)限制服务器的连接的上限(2)连接的重用性等
 */
public class JDBCTools {
    private static DataSource ds;
    private static ThreadLocal<Connection> tl = new ThreadLocal<>();

    static {
        try {
            Properties properties = new Properties();
            properties.load(ClassLoader.getSystemResourceAsStream("druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws Exception{
        Connection connection = tl.get();
        if (connection ==null ){//当前线程还没有拿过连接,就给它从数据库连接池拿一个
            connection = ds.getConnection();
            tl.set(connection);
        }
        return connection;
    }

    public static void free() throws Exception{
        Connection connection = tl.get();
        if (connection != null){
            tl.remove();
            connection.setAutoCommit(true);//避免还给数据库连接池的连接不是自动提交模式(建议)
            connection.close();
        }
    }
}

1、创建BaseDao

主要涉及两个方法

1.通用的增、删、改的方法

创建update方法,涉及两个参数String sql:sql;Object... args:给sql中的?设置的值列表,可以是0~n

 public int update(String sql, Object... args) throws Exception {
 }

创建PreparedStatement对象,对sql预编译

 Connection connection = JDBCTools.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

设置?的值

 if (args != null && args.length > 0) {
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[i]);//?的编号从1开始,不是从0开始,数组的下标是从0开始
            }
        }

执行sql

int len = preparedStatement.executeUpdate();
        preparedStatement.close();

没有开启事务的话,直接回收关闭即可!

if (connection.getAutoCommit()) {
            //回收
            JDBCTools.free();

        }
2.通用的查询多个Javabean对象的方法,例如:多个员工对象,多个部门对象等

这里的clazz接收的是T类型的Class对象, 如果查询员工信息,clazz代表Employee.class, 如果查询部门信息,clazz代表Department.class,

public  <T> ArrayList<T> query(Class<T> clazz, String sql, Object... args) throws Exception {
}

创建PreparedStatement对象,对sql预编译

        Connection connection = JDBCTools.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

设置?的值

 if (args.length > 0 && args != null) {
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[1]);
            }
        }

执行sql

ResultSet resultSet = preparedStatement.executeQuery();

获取结果集的元数据对象

        ArrayList<T> arrayList = new ArrayList<>();
        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
        int count = resultSetMetaData.getColumnCount();

遍历结果集ResultSet,把查询结果中的一条一条记录,变成一个一个T 对象,放到list中

while (resultSet.next()) {
            //循环一次代表有一行,代表有一个T对象
            T t = clazz.newInstance();//要求这个类型必须有公共的无参构造
            //把这条记录的每一个单元格的值取出来,设置到t对象对应的属性中。
            for (int i = 1; i <= count; i++) {
                //for循环一次,代表取某一行的1个单元格的值
                Object value = resultSet.getObject(i);
                //这个值应该是t对象的某个属性值
                //获取该属性对应的Field对象
                //这里再取别名可能没办法对应上
                String columnName = resultSetMetaData.getColumnLabel(i);//获取第i列的字段名或字段的别名
                Field field = clazz.getDeclaredField(columnName);
                field.setAccessible(true);//这么做可以操作private的属性
                field.set(t, value);
            }
            arrayList.add(t);
        }
        resultSet.close();
        preparedStatement.close();

没有开启事务的话,直接回收关闭即可!

 if (connection.getAutoCommit()) {
            //回收
            JDBCTools.free();
        }

2、完整的BaseDao代码

package com.zhangxi.util;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;

/**
 * ClassName: BaseDao
 * Package: com.zhangxi
 */
public class BaseDao {
    /*
   通用的增、删、改的方法
   String sql:sql
   Object... args:给sql中的?设置的值列表,可以是0~n
    */
    public int update(String sql, Object... args) throws Exception {
        //        创建PreparedStatement对象,对sql预编译
        Connection connection = JDBCTools.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //设置?的值
        if (args != null && args.length > 0) {
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[i]);//?的编号从1开始,不是从0开始,数组的下标是从0开始
            }
        }
        //执行sql
        int len = preparedStatement.executeUpdate();
        preparedStatement.close();
        //这里检查下是否开启事务,开启不关闭连接,业务方法关闭!
        //没有开启事务的话,直接回收关闭即可!
        if (connection.getAutoCommit()) {
            //回收
            JDBCTools.free();

        }
        return len;
    }

    /*
   通用的查询多个Javabean对象的方法,例如:多个员工对象,多个部门对象等
   这里的clazz接收的是T类型的Class对象,
   如果查询员工信息,clazz代表Employee.class,
   如果查询部门信息,clazz代表Department.class,
    */
    public  <T> ArrayList<T> query(Class<T> clazz, String sql, Object... args) throws Exception {
        //        创建PreparedStatement对象,对sql预编译
        Connection connection = JDBCTools.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //设置?的值
        if (args.length > 0 && args != null) {
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[1]);
            }
        }
        //执行sql
        ResultSet resultSet = preparedStatement.executeQuery();
         /*
        获取结果集的元数据对象。
        元数据对象中有该结果集一共有几列、列名称是什么等信息
         */
        ArrayList<T> arrayList = new ArrayList<>();
        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
        int count = resultSetMetaData.getColumnCount();

        //遍历结果集ResultSet,把查询结果中的一条一条记录,变成一个一个T 对象,放到list中。
        while (resultSet.next()) {
            //循环一次代表有一行,代表有一个T对象
            T t = clazz.newInstance();//要求这个类型必须有公共的无参构造
            //把这条记录的每一个单元格的值取出来,设置到t对象对应的属性中。
            for (int i = 1; i <= count; i++) {
                //for循环一次,代表取某一行的1个单元格的值
                Object value = resultSet.getObject(i);
                //这个值应该是t对象的某个属性值
                //获取该属性对应的Field对象
                //这里再取别名可能没办法对应上
                String columnName = resultSetMetaData.getColumnLabel(i);//获取第i列的字段名或字段的别名
                Field field = clazz.getDeclaredField(columnName);
                field.setAccessible(true);//这么做可以操作private的属性
                field.set(t, value);
            }
            arrayList.add(t);
        }
        resultSet.close();
        preparedStatement.close();
        //这里检查下是否开启事务,开启不关闭连接,业务方法关闭!
        //没有开启事务的话,直接回收关闭即可!
        if (connection.getAutoCommit()) {
            //回收
            JDBCTools.free();
        }
        return arrayList;
    }

    public <T> T queryBean(Class<T> clazz, String sql, Object... args) throws Exception {
        ArrayList<T> arrayList = query(clazz,sql,args);
        if (arrayList == null  || arrayList.size() ==0){
            return null;
        }
        return arrayList.get(0);
    }

}

四、创建service层

1、完整代码

package com.zhangxi.cms.service;

import com.zhangxi.cms.dao.CustomerDao;
import com.zhangxi.cms.javabean.Customer;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 这是一个具有管理功能的功能类. 内部数据不允许外部随意修改, 具有更好的封装性.
 */
public class CustomerService {


    private CustomerDao customerDao = new CustomerDao();

    /**
     * 用途:返回所有客户对象
     * 返回:集合
     */
    public List<Customer> getList() {

        try {
            return customerDao.queryList();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }



    /**
     * 用途:添加新客户
     * 参数:customer指定要添加的客户对象
     */
    public void addCustomer(Customer customer)  {
        try {
            customerDao.insertCustomer(customer);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 用途:返回指定id的客户对象记录
     * 参数: id 就是要获取的客户的id号.
     * 返回:封装了客户信息的Customer对象
     */
    public Customer getCustomer(int id) {

        try {
            return customerDao.queryById(id);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 修改指定id号的客户对象的信息
     * @param id 客户id
     * @param cust 对象
     * @return 修改成功返回true, false表明指定id的客户未找到
     */
    public boolean modifyCustomer(int id, Customer cust)  {
        int rows = 0;
        try {
            rows = customerDao.updateCustomer(cust);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return rows > 0;
    }

    /**
     * 用途:删除指定id号的的客户对象记录
     * 参数: id 要删除的客户的id号
     * 返回:删除成功返回true;false表示没有找到
     */
    public boolean removeCustomer(int id) {
        int rows = 0;
        try {
            rows = customerDao.deleteCustomer(id);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return rows > 0;
    }

}

五、创建dao层

1、完整代码

package com.zhangxi.cms.dao;

import com.zhangxi.cms.javabean.Customer;
import com.zhangxi.cms.utils.BaseDao;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author 赵伟风
 * Description: 客户进行数据库操作的类
 */
public class CustomerDao extends BaseDao {


    public List<Customer> queryList() throws Exception {
        ArrayList<Customer> list = query(Customer.class, "select * from t_customer");
        return list;
    }

    public void insertCustomer(Customer customer) throws SQLException {
       int rows = update("insert into t_customer(name,gender,age,salary,phone) values (?,?,?,?,?)",
                customer.getName(), customer.getGender(),customer.getAge(),customer.getSalary(),customer.getPhone());
    }

    public Customer queryById(int id) throws Exception {
        Customer customer = queryBean(Customer.class, "select * from t_customer where id = ?", id);
        return customer;
    }

    public int deleteCustomer(int id) throws SQLException {
        return update("delete from t_customer where id =?", id);
    }

    public int updateCustomer(Customer cust) throws SQLException {
        return update("update t_customer set name = ? , gender = ? , age = ? ," +
                "salary = ? , phone = ? where id = ? ;", cust.getName(), cust.getGender(),
                cust.getAge(), cust.getSalary(), cust.getPhone(), cust.getId());
    }
}

六、创建view层

涉及两个类CustomerView、KeyboardUtility,根据注释进行参考

1、KeyboardUtility

package com.zhangxi.cms.view;

import java.util.Scanner;

public class KeyboardUtility {
	
    private static Scanner scanner = new Scanner(System.in);

    public static void readReturn() {
        System.out.print("按回车键继续...");
        readKeyBoard(100, true);
    }

    public static char readMenuSelection() {
        char c;
        for (; ; ) {
            String str = readKeyBoard(1, false);
            c = str.charAt(0);
            if (c != '1' && c != '2' && 
                c != '3' && c != '4' && c != '5') {
                System.out.print("选择错误,请重新输入:");
            } else break;
        }
        return c;
    }

    public static char readChar() {
        String str = readKeyBoard(1, false);
        return str.charAt(0);
    }

    public static char readChar(char defaultValue) {
        String str = readKeyBoard(1, true);
        return (str.length() == 0) ? defaultValue : str.charAt(0);
    }

    public static int readInt() {
        int n;
        for (; ; ) {
            String str = readKeyBoard(8, false);
            try {
                n = Integer.parseInt(str);
                break;
            } catch (NumberFormatException e) {
                System.out.print("数字输入错误,请重新输入:");
            }
        }
        return n;
    }

    public static int readInt(int defaultValue) {
        int n;
        for (; ; ) {
            String str = readKeyBoard(8, true);
            if (str.equals("")) {
                return defaultValue;
            }

            try {
                n = Integer.parseInt(str);
                break;
            } catch (NumberFormatException e) {
                System.out.print("数字输入错误,请重新输入:");
            }
        }
        return n;
    }

    public static String readString(int limit) {
        return readKeyBoard(limit, false);
    }

    public static String readString(int limit, String defaultValue) {
        String str = readKeyBoard(limit, true);
        return str.equals("")? defaultValue : str;
    }

    public static char readConfirmSelection() {
        char c;
        for (; ; ) {
            String str = readKeyBoard(1, false).toUpperCase();
            c = str.charAt(0);
            if (c == 'Y' || c == 'N') {
                break;
            } else {
                System.out.print("选择错误,请重新输入:");
            }
        }
        return c;
    }

    private static String readKeyBoard(int limit, boolean blankReturn) {
        String line = "";

        while (scanner.hasNextLine()) {
            line = scanner.nextLine();
            if (line.length() == 0) {
                if (blankReturn) return line;
                else continue;
            }

            if (line.length() < 1 || line.length() > limit) {
                System.out.print("输入长度(不大于" + limit + ")错误,请重新输入:");
                continue;
            }
            break;
        }

        return line;
    }
}


2、CustomerView

package com.zhangxi.cms.view;

import com.zhangxi.cms.javabean.Customer;
import com.zhangxi.cms.service.CustomerService;

import java.util.List;

/**
 * 这是主控模块, 负责菜单显示和用户交互. 也称为UI, 内部要频繁到管理器对象, 所以使用对象关联
 */
public class CustomerView {

    /**
     * 关联到的管理器对象
     */
    private CustomerService customerService = new CustomerService();

    /**
     * 进入主菜单, 是项目的真正入口, 不可以轻易结束
     */
    public void enterMainMenu() {
        // 1) 声明布尔
        boolean loopFlag = true;
        // 2) 写循环
        do {
            System.out.println("\n--------------------------------客户信息管理--------------------------------------\n");
            listAllCustomers();
            System.out.print("1 添加客户 2 修改客户 3 删除客户 4 客户列表 5 退   出  请选择(1 - 5) : ");
            // 读取用户选择
            char choice = KeyboardUtility.readMenuSelection();
            switch (choice) {
                case '1' : addNewCustomer(); break;
                case '2' : modifyCustomer(); break;
                case '3' : deleteCustomer(); break;
                case '4' : listAllCustomers(); break;
                case '5' :
                    System.out.print("确认是否退出(Y/N) : ");
                    // 获取用户输入的确认
                    char confirm = KeyboardUtility.readConfirmSelection();
                    if (confirm == 'Y') {
                        loopFlag = false;
                    }
                    break;
            }
        } while (loopFlag);
    }

    /**
     * 添加新员工
     */
    private void addNewCustomer() {
        Customer customer = new Customer();
        System.out.println("---------------------添加客户---------------------");
        System.out.print("姓名 : ");
        String name = KeyboardUtility.readString(10);
        customer.setName(name);
        System.out.print("性别 : ");
        String gender = KeyboardUtility.readString(1);
        customer.setGender(gender);
        System.out.print("年龄 : ");
        int age = KeyboardUtility.readInt();
        customer.setAge(age);
        System.out.print("工资 : ");
        int salary = KeyboardUtility.readInt();
        customer.setSalary(salary);
        System.out.print("电话 : ");
        String phone = KeyboardUtility.readString(15);
        customer.setPhone(phone);
        // 通过调用管理器对象完成 员工添加
        customerService.addCustomer(customer);
        System.out.println("---------------------添加完成---------------------");
    }

    /**
     * 修改员工
     */
    private void modifyCustomer () {
        System.out.println("---------------------修改客户---------------------");
        System.out.print("请选择待修改客户ID(-1退出) : ");
        // 获取用户输入的id
        int id = KeyboardUtility.readInt();
        if (id == -1) {
            return;
        }
        // 根据编号定位要修改的目标对象
        Customer target = customerService.getCustomer(id);
        if (target == null) {
            System.out.println("--------------指定ID[" + id + "]的客户不存在-----------------");
            return;
        }
        System.out.println("<直接回车表示不修改>");
        System.out.print("姓名(" + target.getName() + ") : ");
        String name = KeyboardUtility.readString(10, target.getName());
        target.setName(name);
        System.out.print("年龄(" + target.getAge() + ") : ");
        int age = KeyboardUtility.readInt(target.getAge());
        target.setAge(age);
        System.out.print("工资(" + target.getSalary() + ") : ");
        int salary = KeyboardUtility.readInt((int) target.getSalary());
        target.setSalary(salary);
        System.out.print("电话(" + target.getPhone() + ") : ");
        String phone = KeyboardUtility.readString(15, target.getPhone());
        target.setPhone(phone);

        customerService.modifyCustomer(id, target);

        System.out.println("---------------------修改完成---------------------");
    }

    /**
     * 删除员工
     */
    private void deleteCustomer () {
        System.out.println("---------------------删除客户---------------------");
        System.out.print("请选择待删除客户ID(-1退出) : ");
        // 获取用户输入的ID
        int id = KeyboardUtility.readInt();
        if (id == -1) {
            return;
        }
        System.out.print("确认是否删除(Y/N) : ");
        // 获取用户输入的确认
        char confirm = KeyboardUtility.readConfirmSelection();
        if (confirm == 'Y') {
            boolean flag = customerService.removeCustomer(id);
            if (flag) {
                System.out.println("---------------------删除完成---------------------");
            } else {
                System.out.println("--------------指定ID[" + id + "]的客户不存在-----------------");
            }
        }
    }

    /**
     * 员工列表
     */
    private void listAllCustomers() {
        System.out.println("---------------------------------客户列表--------------------------------------");
        // 真的获取所有员工
        List<Customer> list = customerService.getList();
        if (list == null || list.size() == 0) {
            System.out.println("没有数据, 请添加新数据...");
        } else {
            System.out.println("ID\t姓名\t\t性别\t\t年龄\t\t工资\t\t\t电话");
            for (Customer customer : list) {
                System.out.println(customer);
            }
        }
        System.out.println("-----------------------------------------------------------------------------");
    }

}

七、Main方法调用

package com.zhangxi.cms.main;

import com.zhangxi.cms.view.CustomerView;

public class CustomerManage {

    public static void main(String[] args) {
        CustomerView view = new CustomerView();
        view.enterMainMenu();
    }
}

大功告成!!!!! 

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

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

相关文章

玩转云计算:教你在Akamai Linode上构建IT架构–定义项目

时至今日&#xff0c;选择以云计算方式来运维业务&#xff0c;已经成为大部分情况下的最优选。那么如果要从零开始开发一个新应用&#xff0c;并依托云平台来设计、开发、部害和远维&#xff0c;具体该从何处下手&#xff1f;这一系列文章将介绍如何基于Akamai Linode平台实现这…

通过Appium和Xcode Accessibility Inspector获取iOS应用元素定位的方法

在 iOS 移动应用程序上使用选择器查找元素定位是我们在移动端 UI 自动化测试的先决条件。 但是&#xff0c;由于应用程序内容在原生 iOS 应用程序中的呈现方式&#xff0c;我们可以用来定位应用程序元素的选择器与 Web 浏览器元素有很大不同。 在本文中&#xff0c;我们将了解 …

将markdown文档中的图床外链图片下载到本地文件夹

markdown图床外链图片下载到本地代码 前言 因为文章发到先知或者攻防社区需要本地图片&#xff0c;而我的图片从来都是上传到图床&#xff0c;所以编写了一个脚本实现了把markdown文章中所有含有外链图床的图片转储到本地的文件夹。 然后发布文章时再手动一个个上传图片。 详细…

STM32的IAP计数,BootLoader

来源 三种下载方式&#xff1a; 1、ICP&#xff1a;ST-Link, 2、ISP: FlyMcu, 3、IAP IAP简介 IAP技术的核心在于BootLoader程序的设计&#xff0c;这段程序预先烧录在单片机中&#xff0c;正常的APP程序可以使用BootLoader程序中的IAP功能写入&#xff0c;也可以两部分代码一…

comfyui 代码结构分析

comfyui的服务器端是用aiohtttp写的&#xff0c;webui是fastapi直接构建的&#xff0c;但是其实comfyui的这种设计思路是很好的&#xff0c;也许我们不需要在后端起一个复杂的前台&#xff0c;但是可以借助json结构化pipeline&#xff0c;然后利用node节点流把整个流程重新映射…

部署云原生边缘计算平台kubeedge

文章目录 1、kubeedge架构2、基础服务提供 负载均衡器 metallb2.1、开启ipvc模式中的strictARP2.2、部署metalb2.2.1、创建IP地址池2.2.2、开启二层转发&#xff0c;实现在k8s集群节点外访问2.2.3、测试 3、部署cloudcore3.1、部署cloudcore3.2、修改cloudcore的网络类型 4、部…

【ORB-SLAM3】在 Ubuntu20.04 上编译 ORM-SLAM3 并使用 D435i、EuRoC 和 TUM-VI 运行测试

【ORB-SLAM3】在 Ubuntu20.04 上编译 ORM-SLAM3 并使用 D435i、EuRoC 和 TUM-VI 运行测试 1 Prerequisites1.1 C11 or C0x Compiler1.2 Pangolin1.3 OpenCV1.4 Eigen3 2 安装 Intel RealSense™ SDK 2.02.1 测试设备2.2 编译源码安装 (Recommend)2.3 预编译包安装 3 编译 ORB-S…

cesium 创建实体

1、 entity 1.1 entity类型整理 Entity分类 1.2 entity添加 椭圆 const ellipse new Cesium.Entity({position: Cesium.Cartesian3.fromDegrees(114.3, 39.9, 100),ellipse: {semiMinorAxis: 30000, //椭圆的短半轴semiMajorAxis: 40000, //椭圆的长半轴extrudedHeight: 0…

FPGA工程师及其相关岗位招聘~

社区的招聘功能上线之后&#xff0c;许多企业都在上面发布了招聘岗位。 目前有30企业&#xff0c;岗位围绕FPGA工程师&#xff0c;涵盖嵌入式软件工程师、射频工程师、C语言开发、BMC工程师等等&#xff0c;入口放在这里&#xff1a;F学社-全球FPGA技术提升平台 登录账号后&a…

Swift知识点(二)

6. 闭包表达式与闭包 闭包表达式&#xff08;Closure Expression&#xff09; 闭包表达式是一种在简短行内就能写完闭包的语法 也就是&#xff0c;闭包表达式&#xff0c;只是一种简洁、快速实现闭包的语法 Swift 的闭包表达式拥有简洁的风格&#xff0c;鼓励在常见场景中实现…

VLAN的原理及配置

文章目录 一、VLAN的概述1、VLAN的概念2、VLAN的优势 二、静态VLAN三、静态VLAN的配置1.VLAN的范围2.VLAN基本配置 四、Trunk和access的作用参考 一、VLAN的概述 1、VLAN的概念 VLAN就是将网络从逻辑上划分为若按个小的网络&#xff0c;也就是虚拟局域网。 2、VLAN的优势 使…

KingSCADA|如何实现文本显示设备的实时通讯状态?

哈喽,你好啊,我是雷工! 在SCADA项目中,有些要求在界面上实时显示SCADA系统与设备的实时通讯状态,来及时了解PLC或其他设备与SCADA系统的通讯状态是否正常,以及简单的通讯异常分析,在KingSCADA中该如何实现通讯状态的文本显示呢? 接下来用简单的样例介绍KingSCADA如何实…

Vue3尚硅谷张天禹笔记

1. Vue3简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;n 经历了&#xff1a;4800次提交、40个RFC、600次PR、300贡献者 官方发版地址&#xff1a;Release v3.0.0 One Piece vuejs/core 截止2023年10月&#xff0c;最…

整数的反转

给定一个整数&#xff0c;请将该数各个位上数字反转得到一个新数。新数也应满足整数的常见形式&#xff0c;即除非给定的原数为零&#xff0c;否则反转后得到的新数的最高位数字不应为零。 public class _01数字反转 {public static void main(String[] args) {Scanner input n…

二叉树|701.二叉搜索树中的插入操作

力扣题目链接 class Solution { public:TreeNode* insertIntoBST(TreeNode* root, int val) {if (root NULL) {TreeNode* node new TreeNode(val);return node;}if (root->val > val) root->left insertIntoBST(root->left, val);if (root->val < val) r…

【HTWATER】海绵城市关键控制指标一键分析,一键获得整体、单个汇水子面积的年径流总量控制率及污染物削减率的结果

慧天[HTWATER]软件简介 针对城市排水系统基础设施数据管理的需求&#xff0c;以及水文、水力及水质模拟对数据的需求&#xff0c;实现了以数据库方式对相应数据的存储。可以对分流制排水系统及合流制排水系统进行地表水文、管网水力、水质过程的模拟计算。可以对城市低影响开发…

《区块链技术:解锁数字时代的无限可能》

区块链技术作为近年来备受瞩目的创新技术&#xff0c;正以崭新的姿态改变着我们的世界。从技术进展到行业应用&#xff0c;再到面临的挑战与机遇&#xff0c;以及未来的发展趋势&#xff0c;本文将全面剖析区块链技术的发展现状和潜力。 区块链技术原理 区块链技术原理是指构成…

大数据入门(一)

大数据主要要解决&#xff1a;海量数据的采集&#xff0c;存储&#xff0c;分析计算问题。 大数据的特点&#xff1a;大量&#xff08;数据量大&#xff09;&#xff0c;高速&#xff08;数据量的累积越来越快&#xff09;&#xff0c;多样&#xff08;结构化数据和非结构化数…

HTML静态网页成品作业(HTML+CSS+JS)——中华美食八大菜系介绍(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;使用Javacsript代码实现图片轮播切换&#xff0c;共有1个页面。 二、…

逐步学习Go-并发通道chan(channel)

概述 Go的Routines并发模型是基于CSP&#xff0c;如果你看过七周七并发&#xff0c;那么你应该了解。 什么是CSP&#xff1f; "Communicating Sequential Processes"&#xff08;CSP&#xff09;这个词组的含义来自其英文直译以及在计算机科学中的使用环境。 CSP…