手写txt模拟数据库简易框架

news2024/11/23 11:32:52

一.前言

  之前学校让我们写控制台饿了么项目,当时进度没有到数据库,所以用的文本文件txt,来模拟数据库的实现,其实本质上就是一个文件读写,但是简单文件读写并不能包含我们想要的功能,例如条件查询,分页查询等功能,所以我处于好奇,手写了一个简易txt文本数据库框架

二.txt文件准备

  我们先准备几个txt文本文件,来看看他的格式

1.shops.txt商家表

Id    商家名称   商家评分   商家地址   商家简介   商家电话
1001 李家包子 5 牧野区102号 非常美味 123212312
1002 杨铭宇黄焖鸡米饭 4 河师大对面 太好吃了 21312311
1003 王星瑶黄焖鸡米饭 4 河师大对面 太好吃了 21312311
1004 赵家粥铺 4 河师大对面 太好吃了 21312311
1005 蜜雪冰城 4 河师大对面 太好吃了 21312311
1006 台湾卤肉饭 4 河师大对面 太好吃了 21312311
1007 地锅鸡 4 河师大对面 太好吃了 21312311
1008 美味小吃 4 河师大对面 太好吃了 21312311
1009 兰州牛肉拉面 4 河师大对面 太好吃了 21312311
1010 肯德基 4 河师大对面 太好吃了 21312311
1011 德克士 4 河师大对面 太好吃了 21312311
1012 麦当劳 4 河师大对面 太好吃了 21312311
1013 杨铭宇黄焖鸡米饭 4 河师大对面 太好吃了 21312311
1014 杨铭宇黄焖鸡米饭 4 河师大对面 太好吃了 21312311
1015 杨铭宇黄焖鸡米饭 4 河师大对面 太好吃了 21312311
1016 杨铭宇黄焖鸡米饭 4 河师大对面 太好吃了 21312311

2.dishes.txt菜品表

dID shopID 菜品名 介绍 销量 份数 价格
101 1002 蔡徐坤 不好吃 11 10 12.3 
102 1001 包子 无 312 12 12.5 
103 1001 大包子 无 312 31 12.50
104 1001 小包子 无 312 31 12.50
105 1001 中包子 无 312 31 12.50
106 1001 肉包子 无 312 31 12.50
107 1001 肉包子 无 312 31 12.50
108 1001 肉包子 无 312 31 12.50
109 1001 肉包子 无 312 31 12.50
110 1001 肉包子 无 312 31 12.50
111 1001 肉包子 无 312 31 12.50
112 1002 蔡徐坤 不好吃 112 10 12.3 

3.users.txt用户表

ID   用户名   密码   年龄   电话 地址
1001 jjh123 123456 22 1241241234 天堂小区三号楼12层左手户
1002 jfsf 123456 12 1241241234 垃圾小区三号楼12层左手户
681373 zhangsan 123456 123 3123134 地域小区三号楼12层左手户
899803 lisi 12345 18 13123123111 河南省新乡市牧野区河师大对面
663714 lisi123 12345 20 13212331231 河师大对面 

4.orders.txt订单表

ID shopId dishId userId name count singlePrice allPrice address  desc time
001 1001 102 1001 包子 2 12.50 25.00 天堂小区三号楼12层左手户 尽量快一点 2023-10-06T14:43:42.982695700
622975 1001 102 0 包子 1 12.5 12.5 天堂小区三号楼12层左手户 多加糖 2023-10-06T14:43:42.982695700 
708911 1001 102 0 包子 1 12.5 12.5    0  无 2023-10-06T19:45:08.918948500 
955207 1001 102 0 包子 2 12.5 25.0 天堂小区三号楼12层左手户 无 2023-10-25T17:59:15.207836800 
570959 1001 102 0 包子 10 12.5 125.0 天堂小区三号楼12层左手户 快点送达 2023-10-25T18:26:10.996829600 
543529 1001 102 0 包子 2 12.5 25.0 河南省新乡市牧野区河师大对面 多放辣 2023-10-29T11:35:43.542230100 
711960 1001 102 0 包子 2 12.5 25.0 河师大对面 多放辣椒 2023-10-29T11:55:11.967471800 

我们让他的格式看起来尽可能和MySQL中的差不多,然后我们来实现这些查询功能

三.条件构造器

我们知道mybatisplus中有一个条件构造器,querywrapper,你可以构建各种条件,然后来查询

我们来模仿这个条件构造器,来实现我们自己的构造器

(1)QueryBody

public class QueryBody {

    private String key;

    private String value;

    public QueryBody() {
    }

    public QueryBody(String key, String value) {
        this.key = key;
        this.value = value;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "QueryBody{" +
                "key='" + key + '\'' +
                ", value='" + value + '\'' +
                '}';
    }
}

其实就是一个key和对应的value,然后我们在来构建条件

(2)QueryWrapper

/**
 * 查询条件
 */
public class QueryWrapper {

    /**
     * 参数集合
     */
    private  List<QueryBody> queryArgs = new ArrayList<>();

    public QueryWrapper(){}

    /**
     * 相等条件
     */
    public QueryWrapper eq(String key,String arg){
        QueryBody queryBody = new QueryBody(key,arg);
        queryArgs.add(queryBody);
        return this;
    }

    public List<QueryBody> getQueryArgs() {
        return queryArgs;
    }

这里为了简单我只实现了等值条件查询eq(),

注意:我们返回的是this,这个对象本身,这样就可以实现链式编程了

四.分页结果类PageBody

/**
 * 对分页的封装
 */
public class PageBody {
    /**
     * 总条数
     */
    private int total;
    /**
     * 当前的页数
     */
    private int currntPage;
    /**
     * 当前每页的尺寸
     */
    private int size;
    /**
     * 总页数
     */
    private int pageSize;
    /**
     * 结果集
     */
    private List<Object> results;

    public PageBody() {
    }

    public PageBody(int total, int currntPage, int size, int pageSize, List<Object> results) {
        this.total = total;
        this.currntPage = currntPage;
        this.size = size;
        this.pageSize = pageSize;
        this.results = results;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
        //设置总页数
        if(size!=0){
            this.pageSize = total / size +1;
        }

    }

    public int getCurrntPage() {
        return currntPage;
    }

    public void setCurrntPage(int currntPage) {
        this.currntPage = currntPage;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public int getPageSize() {
        return pageSize;
    }

//    public void setPageSize(int pageSize) {
//        this.pageSize = pageSize;
//    }

    public List<Object> getResults() {
        return results;
    }

    public void setResults(List<Object> results) {
        this.results = results;
    }

    @Override
    public String toString() {
        return "PageBody{" +
                "total=" + total +
                ", currntPage=" + currntPage +
                ", size=" + size +
                ", pageSize=" + pageSize +
                ", results=" + results +
                '}';
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;

    }
}

大致上和mybatispllus的page对象差不多

五.FileUtils工具类

该框架其实就是一个工具类,实现了大量的方法

/**
 * 文件工具类
 * @author JJH
 */
public class FileUtils {

  ......
}

我们把每个方法截取出来一个一个分析

返回属性get方法的工具方法

  private static String getXxx(String name){

     return "get" + name.substring(0,1).toUpperCase()
              + name.substring(1);

  }

1.根据文件路径将文件内容返回为集合

   /**
     * 根据文件路径将文件内容返回为集合
     * @param path 文件路径
     * @param clazz 要返回对象的类型
     * @return 对象集合
     */
 public static  List<Object> fileToList(String path, Class<?> clazz) {

      List<Object> list = new ArrayList<>();

      BufferedReader br = null;
      try {
          br = new BufferedReader(new FileReader(path));
          //读掉第一行数据(表头)
          br.readLine();
          String row;
          while ((row=br.readLine()) != null) {
              //先把对象创建出来
              Object obj = clazz.newInstance();
              //获取每一个元素
              String[] s = row.split(" ");
              //获取属性集合
              Field[] fields = clazz.getDeclaredFields();
              for (int i=0;i<fields.length;i++) {
                  //获取属性的类型
                  Class<?> type = fields[i].getType();
                  String name = fields[i].getName();
                String setXxx="set"+name.substring(0,1).toUpperCase()+name.substring(1);
                 //获取set方法
                  Method setMethod = clazz.getDeclaredMethod(setXxx,type);
                  //把参数类型转换一下
                  String s1 = s[i];
                  Object arg = TypeUtils.getInstanceByType(s1, type);
                  //调用set方法给属性赋值
                  setMethod.invoke(obj,arg);
              }
               //装入集合中
              list.add(obj);
          }
          return list;
      } catch (IOException | InvocationTargetException | NoSuchMethodException | InstantiationException |
               IllegalAccessException e) {
          throw new RuntimeException(e);
      } finally {
          try {
              assert br != null;
              br.close();
          } catch (IOException e) {
              throw new RuntimeException(e);
          }
      }


  }

主要使用了反射,传入文件的路径和要返回集合中对象的类型,这样就可以根据反射来获取属性然后给属性赋值了

2.将集合保存到文件中去

 /**
     * 将集合保存到文件中去
     * @param list 要保存的结合
     * @param path 文件路径
     * @param clazz 对象的类型
     * @return 是否保存成功
     * @param
     */
 public static  boolean ListToFile(List<Object> list, String path, Class<?> clazz){

      BufferedWriter bw = null;
      try {
          //第二个参数是允许追加写入
         bw = new BufferedWriter(new FileWriter(path,true));

          StringBuilder sb = new StringBuilder();
          for (Object obj : list) {

              //先获取对象的属性
              Field[] fields = clazz.getDeclaredFields();
              for (Field field : fields) {
                 //将第一个字母转化为大写
                  String name = field.getName();
                  String getXxx = "get"+name.substring(0, 1).toUpperCase()
                          + name.substring(1);
                 //调用get方法获取属性值
                  Method getMethod = clazz.getDeclaredMethod(getXxx);
                  String str = getMethod.invoke(obj).toString();
                  sb.append(str).append(" ");
              }
                sb.append("\n");
          }
             bw.write(sb.toString());

      } catch (Exception e) {
          throw new RuntimeException(e);
      } finally {
          try {
              assert bw != null;
              bw.close();
          } catch (IOException e) {
              throw new RuntimeException(e);
          }
      }


      return true;
  }

3.返回文件的行数

 /**
     * 返回文件的行数
     * @param path 文件路径
     * @return 行数
     * @throws IOException
     */
  public static int getFileRow(String path) throws IOException {
     BufferedReader br = new BufferedReader(new FileReader(path));
     int sum =0;
     while (true){
         String str = br.readLine();
         if(str!=null){
             sum++;
         }else {
             break;
         }
     }
     return sum-1; //第一行不算
  }

4.模拟分页查询

 /**
     * 模拟分页查询
     * @param page 页数
     * @param size 尺寸
     * @param path 文件路径
     * @param clazz 返回集合中对象的类型
     * @return  对象集合
     */
  public static List<Object> pageList(int page,int size,String path, Class<?> clazz) {

      /*
          计算开始位置,第一行不算,所以是从第二行开始
          2-11为第一页了,
          12-22为第二页
          23-33为第三页
          start = 2 + (page-1)*size
          当我们最后一页不满的时候,如果要把这一页剩余的部分
          查出来,直接查询会报错误,我们需要判断最后一页还有多少
          余量,让我们最后一次循环次数等于这个余量,不要让它越界
       */

      List<Object> list = new ArrayList<>();
      try {
          //先获取总的条数,第一行不算
          int total = getFileRow(path) - 1;
          //计算一下最后一页有多少剩余(求余)
          int leastSize = total % size;

          BufferedReader br = new BufferedReader(new FileReader(path));
          //先让它读到start
          int start = 2 + (page - 1) * size;
          for (int i = 1; i < start; i++) {
              br.readLine();
          }
          //判断一下循环的次数,看看是满的,还是最后一页剩余的
          int num = total - (page-1) * size;
          int loop ; //循环次数
          if(leastSize==0||num>=10){
              loop = size;
          }else {
              loop = leastSize-1;
          }
          //然后让它读size次,默认为10
          for (int i = 0; i < loop; i++) {
              String row = br.readLine();
              //先把对象创建出来
              Object obj = clazz.newInstance();
              //获取每一个元素
              String[] s = row.split(" ");
              //获取属性集合
              Field[] fields = clazz.getDeclaredFields();
              for (int j = 0; j < fields.length; j++) {
                  //获取属性的类型
                  Class<?> type = fields[j].getType();
                  String name = fields[j].getName();
                  String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                  //获取set方法
                  Method setMethod = clazz.getDeclaredMethod(setXxx, type);
                  //把参数类型转换一下
                  String s1 = s[j];
                  Object arg = TypeUtils.getInstanceByType(s1, type);
                  //调用set方法给属性赋值
                  setMethod.invoke(obj, arg);
              }
              //装入集合中
              list.add(obj);
          }
      }catch (Exception e){
          e.printStackTrace();
      }
      return list;
  }

5. 根据相等条件分页查询

 /**
     * 根据相等条件分页查询
     * @param page 页数
     * @param size 尺寸
     * @param path 文件路径
     * @param clazz 集合对象类型
     * @param wrapper 条件构造器
     * @return 对象集合
     */
  public static List<Object> pageQueryList(int page, int size, String path, Class<?> clazz, QueryWrapper wrapper){
         //把条件构造器中的条件拿出来
      List<QueryBody> querybodys = wrapper.getQueryArgs();


      List<Object> list = new ArrayList<>();
      List<Object> resList = new ArrayList<>();
      try {
          BufferedReader br = new BufferedReader(new FileReader(path));
          br.readLine(); // 先把第一行读了

          int rows = getFileRow(path);
          for(int i=0;i<rows-1;i++){
              String str = br.readLine();
              //先把对象创建出来
              Object obj = clazz.newInstance();
              //获取每一个元素
              String[] s = str.split(" ");
              //获取属性集合
              Field[] fields = clazz.getDeclaredFields();
              for (int j = 0; j < fields.length; j++) {
                  //获取属性的类型
                  Class<?> type = fields[j].getType();
                  String name = fields[j].getName();
                  String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                  //获取set方法
                  Method setMethod = clazz.getDeclaredMethod(setXxx, type);
                  //把参数类型转换一下
                  String s1 = s[j];
                  Object arg = TypeUtils.getInstanceByType(s1, type);
                  //调用set方法给属性赋值
                  setMethod.invoke(obj, arg);
              }
              //装入集合中
              list.add(obj);
          }
      }catch (Exception e){
          e.printStackTrace();
      }
        // list.forEach(System.out::println);
      //以上是拿到了所有的元素,下面我们来对元素先进行一个筛选
      try {
          for (QueryBody querybody : querybodys) {
              //对每个条件进行过滤
              String key = querybody.getKey();
              String value = querybody.getValue();
              //每次先清空
              resList.removeAll(resList);
              for (Object obj:list) {
                      String getXxx = getXxx(key);
                      //调用get方法来获取属性值
                      Method getMethod = clazz.getDeclaredMethod(getXxx);
                      String res = getMethod.invoke(obj).toString();
                      //比对条件是否相等
                  if(res.equals(value)){
                      resList.add(obj);
                  }
              }

          }
      } catch (Exception e) {
          throw new RuntimeException(e);
      }
    // resList.forEach(System.out::println);
     // 如果不传page和size,默认就全查
      if(Objects.isNull(page)&&Objects.isNull(size)){
          return resList;
      }
      ArrayList<Object> pageList = new ArrayList<>();
      //分页查询
      /**
       * 0-9 第一页
       * 10-19 第二页
       * 20-21 第三页
       * 还是得先判断一下最后一页的剩余问题
       *
       */
      int start = (page-1)*size;
      for(int i = 0;i<resList.size();i++){
              if(i==start){


                  if(resList.size()<=size){
                      size = resList.size();
                  }else {
                      //多于一页,算一下余量
                      int mod = resList.size()%size;
                      if(mod>0){
                          //计算当前页面
                          int currentPage = start/size+1 ;
                          //算一下之前的总数据量是否
                          if(mod+(currentPage*size-1) < currentPage*size){
                              size = mod;
                          }
                      }
                  }

                  for(int j = start; j < (start+size); j++){
                      pageList.add(resList.get(j));
                      //pageList.forEach(System.out::println);
                  }
                  break;
              }
      }
     // pageList.forEach(System.out::println);
      return pageList;
  }

6.分页查询的默认全查形式,方法重载

/**
     * 分页查询的默认全查形式,方法重载
     * @param path 文件路径
     * @param clazz 对象类型
     * @param wrapper 条件构造器
     * @return  对象集合
     */
    public static List<Object> pageQueryList(String path, Class<?> clazz, QueryWrapper wrapper){
        //把条件构造器中的条件拿出来
        List<QueryBody> querybodys = wrapper.getQueryArgs();

        List<Object> list = new ArrayList<>();
        List<Object> resList = new ArrayList<>();
        try {
            BufferedReader br = new BufferedReader(new FileReader(path));
            br.readLine(); // 先把第一行读了

            String row;
            while ((row=br.readLine())!=null){
                //先把对象创建出来
                Object obj = clazz.newInstance();
                //获取每一个元素
                String[] s = row.split(" ");
                //获取属性集合
                Field[] fields = clazz.getDeclaredFields();
                for (int j = 0; j < fields.length; j++) {
                    //获取属性的类型
                    Class<?> type = fields[j].getType();
                    String name = fields[j].getName();
                    String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                    //获取set方法
                    Method setMethod = clazz.getDeclaredMethod(setXxx, type);
                    //把参数类型转换一下
                    String s1 = s[j];
                    Object arg = TypeUtils.getInstanceByType(s1, type);
                    //调用set方法给属性赋值
                    setMethod.invoke(obj, arg);
                }
                //装入集合中
                list.add(obj);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        //以上是拿到了所有的元素,下面我们来对元素先进行一个筛选
        try {
            for (QueryBody querybody : querybodys) {
                //对每个条件进行过滤
                String key = querybody.getKey();
                String value = querybody.getValue();
               // System.out.println(key+":"+value);
                //每次先清空
                resList.removeAll(resList);
                for (Object obj:list) {
                    String getXxx = getXxx(key);
                    //调用get方法来获取属性值
                    Method getMethod = clazz.getDeclaredMethod(getXxx);
                    Object res = getMethod.invoke(obj);
                    //比对条件是否相等
                    if(res.toString().equals(value)){
                        resList.add(obj);
                    }
                }

            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return resList;
    }

7.根据主键修改改行数据

 /**
     * 根据主键修改改行数据
     * @param
     * @param
     */
    public static boolean updateOne(String path, Object obj) {

        Class<?> aClass = obj.getClass();
        StringBuilder updateRow = new StringBuilder();
        Method getMethod = null;
        String str = null;
        String id = null;

        Field[] fields = aClass.getDeclaredFields();
        for (int i = 0;i<fields.length;i++) {
            try {
                getMethod = aClass.getDeclaredMethod(getXxx(fields[i].getName()));
                str = getMethod.invoke(obj).toString();
                updateRow.append(str).append(" ");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            if(i==0){
                id = str;
            }
        }


        StringBuilder sb = new StringBuilder();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(Paths.get(path))));
            //先把表头添加上
            String head = reader.readLine();
            sb.append(head).append("\r\n");

            int rows = getFileRow(path);

            for (int i = 0; i <rows ; i++) {
                String row = reader.readLine();
                String Id = row.split(" ")[0];
                if(id.equals(Id)) {
                   sb.append(updateRow).append("\r\n");
                }else {
                    sb.append(row).append("\r\n");
                }
            }
            //再把文件写回去
            BufferedWriter writer = new BufferedWriter(new FileWriter(path));

            writer.write(sb.toString());

           reader.close();
           writer.close();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }


         return true;

    }

六.测试数据

我们来测试一下查询效果

可以看到,这时默认的全部查询方式,

 

可以看到,这是等值条件查询,查询到了包子店铺的菜品,

综上所述,我们实现了自己的txt文本数据库简易框架,当然还有很多功能不完善,下次希望可以模拟sql语句来实现查询,或者模拟一下事务的实现

 

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

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

相关文章

【算法秘籍】藏在0和1之间的秘密,助你码出优秀人生

《算法秘籍》双十一 5折购书&#xff0c;就在京东商城 数据结构和算法是计算机科学的基石&#xff0c;是计算机的灵魂&#xff0c;要想成为计算机专业人员&#xff0c;学习和掌握算法是十分必要的。不懂数据结构和算法的人不可能写出效率更高的代码。计算机科学的很多新行业都离…

Discord将切换到临时文件链接以阻止恶意软件传播

导语 Discord是一个广受欢迎的社交平台&#xff0c;但其服务器长期以来一直是恶意活动的温床。为了解决这个问题&#xff0c;Discord决定采取行动&#xff0c;将切换到临时文件链接&#xff0c;以阻止恶意软件的传播。本文将介绍Discord的最新举措&#xff0c;并探讨其对用户安…

C盘清理指南(三)——文件目录更改

各位小伙伴你们好&#xff0c;今天的推送是C盘清理系列的第三期——文件路径更改&#xff0c;分为文件夹路径和软件默认路径两个模块。 一&#xff0e;文件夹路径更改 点击进入C盘&#xff0c;依次点击上方“查看——隐藏的项目”&#xff0c;可以看到C盘中各种隐藏目录。 单击…

kafka微服务学习

消息中间件对比&#xff1a; 1、吞吐、可靠性、性能 Kafka安装 Kafka对于zookeeper是强依赖&#xff0c;保存kafka相关的节点数据&#xff0c;所以安装Kafka之前必须先安装zookeeper Docker安装zookeeper 下载镜像&#xff1a; docker pull zookeeper:3.4.14创建容器 do…

Linux 下最主流的文件系统格式——ext

硬盘分成相同大小的单元&#xff0c;我们称为块&#xff08;Block&#xff09;。一块的大小是扇区大小的整数倍&#xff0c;默认是 4K。在格式化的时候&#xff0c;这个值是可以设定的。 一大块硬盘被分成了一个个小的块&#xff0c;用来存放文件的数据部分。这样一来&#xf…

操作系统 day06(进程控制、原语)

进程控制的概念 原语 怎么实现进程控制—用原语实现 如果不能一气呵成&#xff0c;那么会出现操作系统中的某些关键数据结构信息不统一的情况&#xff0c;这会影响操作系统进行别的管理工作&#xff0c;如下图所示&#xff1a; 原语的原子性怎么实现 正常情况下&#xff…

Source insight 创建工程研读库源码

下载库文件解压 创建工程添加路径 添加文件到工程 同步文件 下载库文件解压 创建工程添加路径 添加文件到工程 同步文件 数据库更新 强制重新分析所有文件仅同步当前源文件 添加和删除文件 自动添加新文件从项目中删除丢失的文件

程序员想要网上接单?那这几点注意事项你可要记好了!不看后悔!

相信网上接单对于程序员来说并不陌生&#xff0c;甚至有些程序员还以此为主业&#xff0c;靠网上接单来增加收入&#xff0c;维持生计&#xff0c;但是你真的确定你懂网上接单的套路吗&#xff1f;你知道网上接单的注意事项吗&#xff1f;这期文章就来盘点一下&#xff0c;无论…

跟着森老师学React Hooks(1)——使用Vite构建React项目

Vite是一款构建工具&#xff0c;对ts有很好的支持&#xff0c;最近也是在前端越来越流行。 以往的React项目的初始化方式大多是通过脚手架create-react-app(本质是webpack)&#xff0c;其实比起Vite来构建&#xff0c;启动会慢一些。 所以这次跟着B站的一个教程&#xff0c;使用…

JavaWeb Day05 前后端请求响应与分层解耦

目录 一、请求与响应 &#xff08;一&#xff09;请求的参数接收 ①数组参数 ②集合参数 ③日期参数 ④json参数 ⑤路径参数 总结 &#xff08;二&#xff09;响应 ①简单文本text ②数组 ③列表 ④同一响应数据格式 ⑤总结 二、三层架构与分层解耦 &#xff0…

Windows下MSYS2下载与安装

下载地址&#xff1a; 官网下载地址 https://www.msys2.org/阿里云镜像下载 https://mirrors.aliyun.com/msys2/distrib/x86_64/https://mirrors.aliyun.com/msys2/distrib/x86_64/msys2-x86_64-20231026.exe?spma2c6h.25603864.0.0.12b92551XW5OSM官网下载 ![官网下载](htt…

程序员怎样才能学好算法,推荐好书送给大家

前言 数据结构和算法是计算机科学的基石&#xff0c;是计算机的灵魂 要想成为计算机专业人员&#xff0c;学习和掌握算法是十分必要的。不懂数据结构和算法的人不可能写出效率更高的代码。计算机科学的很多新行业都离不开数据结构和算法作为基石&#xff0c;比如大数据、人工…

【AICFD案例教程】轴流风扇仿真分析

AICFD是由天洑软件自主研发的通用智能热流体仿真软件&#xff0c;用于高效解决能源动力、船舶海洋、电子设备和车辆运载等领域复杂的流动和传热问题。软件涵盖了从建模、仿真到结果处理完整仿真分析流程&#xff0c;帮助工业企业建立设计、仿真和优化相结合的一体化流程&#x…

Jmeter接口自动化测试操作流程

在企业使用jmeter开展实际的接口自动化测试工具&#xff0c;建议按如下操作流程&#xff0c; 可以使整个接口测试过程更规范&#xff0c;更有效。 接口自动化的流程&#xff1a; 1、获取到接口文档&#xff1a;swagger、word、excel ... 2、熟悉接口文档然后设计测试用例&am…

QT第2课-GUI程序实例分析

GUI程序开发概述 不同的操作系统GUI开发原理相同不同的操作系统GUI SDK 不同 GUI 程序开发原理 GUI程序在运行时会创建一个消息队列系统内核将用户的键盘鼠标操作翻译成对应的程序消息程序在运行过程中需要实时处理队列中的消息当队列中没有消息时&#xff0c;程序将处于停滞…

第23章(上)_索引原理之索引与约束

文章目录 索引索引分类主键选择索引的代价 约束外键约束约束与索引的区别 索引使用场景不要使用索引的场景总结 索引 索引的概念&#xff1a;索引是一种有序的存储结构。索引按照单个或多个列的值进行排序。 索引的目的&#xff1a;提升搜索效率。 索引分类 按照数据结构分为…

通达OA V12版,引入thinkphp5.1框架,及获取session

通达OA V12版&#xff0c;引入thinkphp5.1框架 如下过程引入 如下过程引入 在D:/MYOA/webroot目录下&#xff0c;通过composer安装thinkphp5.1框架。在tp框架下&#xff0c;找到文件&#xff1a;thinkphp\library\think下的Error.php。方案1&#xff1a;截断异常输出 代码如…

js处理赎金信

给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1&#xff1a; 输入&…

栈的应用:表达式求值(中缀表达式,后缀表达式,前缀表达式)

目录 1.三种算术表达式1.中缀表达式2.后缀表达式3.前缀表达式 2.后缀表达式相关考点1.中缀表达式转后缀表达式1.手算方法2.例题3.机算 2.后缀表达式求值1.手算方法2.机算 3.前缀表达式相关考点1.中缀表达式转前缀表达式1.手算方法2.例题 2.前缀表达式求值 4.中缀表达式求值 1.三…

无人机航拍技术基础入门,无人机拍摄的方法与技巧

一、教程描述 买了无人机&#xff0c;可是我不敢飞怎么办&#xff1f;禁飞区越来越多&#xff0c;到底哪儿才能飞&#xff1f;我的无人机跟你一样&#xff0c;为什么我拍不出大片&#xff1f;厂家的说明书看不进去&#xff0c;有没有一套无人机的课程&#xff0c;可以快速上手…