Android——数据存储(二)(二十二)

news2024/11/26 14:49:37

1. SQLite数据库存储

1.1 知识点

(1)了解SQLite数据库的基本作用;

(2)掌握数据库操作辅助类:SQLiteDatabase的使用;

(3)可以使用命令操作SQLite数据库;

(4)可以完成数据库的CRUD操作;

(5)掌握数据库查询及Cursor接口的使用。

1.2 具体内容

在Android当中,本身提供了一种微型的嵌入式数据库叫做SQLite,同样可以执行SQL语句,对于不熟悉sql和jdbc的小伙伴,还是需要去自学一下。

下面我们首先使用一段代码演示如何取得数据库表操作。

package com.example.sqliteopenhelper;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class MySQLiteOpenHelper extends SQLiteOpenHelper {
    public static final String DATABASENAME="wancy";//数据库名称
	public static final int DATABASEVERSION=1;//版本号
	public static final String TABLENAME = "DH10";//数据库表名
	
	public MySQLiteOpenHelper(Context context) {
		super(context, DATABASENAME, null, DATABASEVERSION);
		// TODO Auto-generated constructor stub
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		String sql = "create table "+TABLENAME+" (id INTEGER PRIMARY KEY,"+
	                 "name VARCHAR(50) NOT NULL,"+"birthday DATE NOT NULL)";
		db.execSQL(sql);
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		String sql = "drop table if exists "+TABLENAME;//当退出的时候删除表
        db.execSQL(sql);
        this.onCreate(db);
	}

}

以上要注意一点,在SQLite当中如果想要让某个字段自动增长,那么在创建表的时候使用“INTEGER PRIMARY KEY”声明即可。

那么这样的话一个数据库辅助类已经定义好了,那么我们下面在Activity当中去调用此类的方法。

package com.example.sqliteproject;

import com.example.sqliteopenhelper.MySQLiteOpenHelper;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class SQLiteActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_sqlite);
		
		MySQLiteOpenHelper helper = new MySQLiteOpenHelper(this);
		helper.getWritableDatabase();//表示以读写的形式打开数据库
		
	}


}

现在已经取得了数据库的连接了,如果以上代码没有错误,运行之后就可以在文件列表当中找到数据表.FileExplorer/data/data/数据库辅助类所在的包/database。根据代码,可以发现,如果数据库不存在,那么会自动调用onCreate方法去创建表,如果数据库已经存在了,但是版本号发生了改变,将会调用onUpgrade方法,现将原来的表删除之后,在去创建新的表。

·使用SQLite数据库并完成数据库的更新操作。

public void insert(String name,String birthday){
		SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象
		String sql = "insert into "+TABLENAME+" (name,birthday) values ('"+name+"',"+birthday+")";
		db.execSQL(sql);
		db.close();
	}
	public void update(int id,String name,String birthday){
		SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象
		String sql = "update "+TABLENAME+" set name='"+name+"',birthday="+birthday+" where id="+id;
		db.execSQL(sql);
		db.close();
	}
	public void delete(int id){
		SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象
		String sql = "delete from "+TABLENAME+" where id="+id;
		db.execSQL(sql);
		db.close();
	}

以上增删改三个方法写完之后,就可以在Activity当中去进行调用。

package com.example.sqliteproject;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import com.example.sqliteopenhelper.MySQLiteOpenHelper;

public class SQLiteActivity extends Activity {
	MySQLiteOpenHelper helper=null;
	Button insert,update,del = null;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_sqlite);
		
		insert=(Button) super.findViewById(R.id.insert);
		update = (Button) super.findViewById(R.id.update);
		del = (Button) super.findViewById(R.id.del);
		helper = new MySQLiteOpenHelper(this);
		helper.getWritableDatabase();//表示以读写的形式打开数据库
		insert.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				helper.insert("毛栗子", "1995-01-05");
				Toast.makeText(SQLiteActivity.this, "新增成功", 0).show();
			}
		});
		update.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				helper.update(1, "大白兔", "1995-01-05");
				Toast.makeText(SQLiteActivity.this, "修改成功", 0).show();
			}
		});
		del.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				helper.delete(1);
				Toast.makeText(SQLiteActivity.this, "删除成功", 0).show();
			}
		});
	}


}

以上的程序,所有数据都是固定的,这在实际开发当中显然是不科学的,因为我们至少也要使用编辑框进行数据的编辑才是符合实际,而且使用字符串拼凑sql这种形式也是存在问题的,那么我们可以使用占位符的形式来处理这种问题。

public void insert(String name,String birthday){
		SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象
		java.sql.Date date = null;
		try {
			date = new java.sql.Date(new SimpleDateFormat("yyyy-MM-dd").parse(birthday).getTime());
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		String sql = "insert into "+TABLENAME+" (name,birthday) values (?,?)";//使用占位符
		Object args[] = new Object[]{name,birthday};
		db.execSQL(sql,args);
		db.close();
	}

对于以上程序,只是换了另一种操作方法来解决拼凑的问题,功能上没有变化。

对于拼凑sql和使用占位符,可以形成一个共识:

肯定是使用占位符更好一些。

在android当中,还对数据的封装提供了一个ContentValues类。 可以理解为一个Map集合,有key和value,唯一不同的是ContentValues中的key必须是字符串。以后的操作就可以直接通过key取得value。并将value设置到sql语句当中。

public void insert(String name,String birthday){
		SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象
		ContentValues cv = new ContentValues();
		cv.put("name", name);
		cv.put("birthday", birthday);
		db.insert(TABLENAME, null, cv);//进行新增操作
		db.close();
	}
	public void update(int id,String name,String birthday){
		SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象
		ContentValues cv = new ContentValues();
		cv.put("name", name);
		cv.put("birthday", birthday);
		String whereClause = " id=?";
		String whereArgs[]= new String[]{String.valueOf(id)};
		db.update(TABLENAME, cv, whereClause, whereArgs);//更新操作
		db.close();
	}
	public void delete(int id){
		SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象
		String whereClause = " id=?";
		String whereArgs[]= new String[]{String.valueOf(id)};
		db.delete(TABLENAME, whereClause, whereArgs);//删除操作
		db.close();
	}

那么对于使用占位符和ContentValues进行数据库更新操作,两种方式并没有严格的优劣之分,但是对于不会sql的开发人员来说,使用ContentValues更好的。

·数据库查询机Cursor接口

在JDBC中ResultSet接口不呢是的功能就是依靠一个next()方法一动指针向下取数据,是到了JDBC2.0之后才能够向上取数据,但是我们一般也不去用这种向上取的形式。

Cursor接口,出现的比ResultSet晚,所有操作机制有些不同。

package com.example.sqliteproject;

import java.util.ArrayList;
import java.util.List;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class DH10Cursor {
      private static final String TABLENAME="PR10";
      private SQLiteDatabase db =null;
	public DH10Cursor(SQLiteDatabase db) {
		super();
		this.db = db;
	}
    
	public List<String> find(){
		List<String> all = new ArrayList<String>();
		String sql = "select id,name,birthday from "+TABLENAME;
		Cursor result = this.db.rawQuery(sql, null);//执行查询语句
		//采用循环的形式去结果集中的数据
		for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){
			all.add(result.getInt(0)+"====="+result.getString(1)+"====="+result.getString(2));
		}
		result.close();
		db.close();
		return all;
	}
}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/mylayout"
    tools:context=".SQLiteActivity" >

   <Button
       android:id="@+id/insert"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="新增"
       />
   <Button
       android:id="@+id/update"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="修改"
       />
   <Button
       android:id="@+id/del"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="删除"
       />
   <Button
       android:id="@+id/query"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="查询"
       />
       
</LinearLayout>

package com.example.sqliteproject;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Toast;

import com.example.sqliteopenhelper.MySQLiteOpenHelper;

public class SQLiteActivity extends Activity {
	MySQLiteOpenHelper helper=null;
	Button insert,update,del,query = null;
	ListView listView = null;
	LinearLayout myLayout = null;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_sqlite);
		helper = new MySQLiteOpenHelper(this);
		insert=(Button) super.findViewById(R.id.insert);
		update = (Button) super.findViewById(R.id.update);
		del = (Button) super.findViewById(R.id.del);
		query = (Button) super.findViewById(R.id.query);
		myLayout = (LinearLayout) super.findViewById(R.id.mylayout);
		query.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				SQLiteActivity.this.listView = new ListView(SQLiteActivity.this);
				listView.setAdapter(new ArrayAdapter<String>(SQLiteActivity.this, android.R.layout.simple_list_item_1,
						new DH10Cursor(SQLiteActivity.this.helper.getWritableDatabase()).find()));
				myLayout.addView(listView);
				
			}
		});
		
		
		insert.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				helper.insert("毛栗子", "1995-01-05");
				Toast.makeText(SQLiteActivity.this, "新增成功", 0).show();
			}
		});
		update.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				helper.update(1, "大白兔", "1995-01-05");
				Toast.makeText(SQLiteActivity.this, "修改成功", 0).show();
			}
		});
		del.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				helper.delete(1);
				Toast.makeText(SQLiteActivity.this, "删除成功", 0).show();
			}
		});
	}


}

需要注意一下Cursor的下标是从0开始的有别于ResultSet

·模糊查询

     ·使用sql语句完成模糊查询

public List<String> find(){
		List<String> all = new ArrayList<String>();
		String sql = "select id,name,birthday from "+TABLENAME+" where name like ?";
		String args[] = new String[]{"%栗%"};
		Cursor result = this.db.rawQuery(sql, args);//执行查询语句
		//采用循环的形式去结果集中的数据
		for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){
			all.add(result.getInt(0)+"====="+result.getString(1)+"====="+result.getString(2));
		}
		result.close();
		db.close();
		return all;
	}

        ·使用query方法完成

public List<String> find(){
		List<String> all = new ArrayList<String>();
		//String sql = "select id,name,birthday from "+TABLENAME+" where name like ?";
		String selection = "name like ?";
		String args[] = new String[]{"%栗%"};
		String columns[] = new String[]{"id","name","birthday"};
		Cursor result = this.db.query(TABLENAME, columns, selection, args, null, null, null);//执行查询语句
		//采用循环的形式去结果集中的数据
		for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){
			all.add(result.getInt(0)+"====="+result.getString(1)+"====="+result.getString(2));
		}
		result.close();
		db.close();
		return all;
	}

既然模糊查询已经能够完成了,那么还有一种功能可以往下去实现,那就是数据的分页。如果想要实现数据的部分显示,这个语句和Mysql中的查询方式是非常相似,使用limit完成。下面我们进行一些简单的分页操作。

public List<String> find(){
		int currentPage = 1;//当前页码
		int lineSize = 5;//每页显示的数据量
		List<String> all = new ArrayList<String>();
		String sql = "select id,name,birthday from "+TABLENAME+" limit ?,?";
		String args[] = new String[]{String.valueOf((currentPage-1)*lineSize),String.valueOf(currentPage*lineSize)};
		Cursor result = this.db.rawQuery(sql, args);
		//采用循环的形式去结果集中的数据
		for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){
			all.add(result.getInt(0)+"====="+result.getString(1)+"====="+result.getString(2));
		}
		result.close();
		db.close();
		return all;
	}

·使用ListView来实现滑动分页

  Android中有这样一个操作,只需要手指进行上下滑动,屏幕自动滚动,到达最后一条数据的时候,提示:请稍等,数据正在加载......。这个操作需要使用SimpleAdapter来完成,因为在这个适配器中有下面这样一个方法。

pulibc void notifyDataSetChanged()

表示如果在SimpleAdapter中的填充数据集合list内容一旦发生变化,就会立刻通知ListView进行及时新数据加载,当数据加载底部的时候,需要提示一个信息,而这个信息可以通过ListView组件里的方法去添加

public void addFooterView(View v)

现在还剩下一个问题,需要去监听滚动事件,需要使用如下接口:

首先顶一个ListView的布局模板。

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mylayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TableRow >
        <TextView 
            android:id="@+id/id"
            android:layout_width="50px"
            android:layout_height="wrap_content"
            android:textSize="30px"
        />
        <TextView 
            android:id="@+id/name"
            android:layout_width="120px"
            android:layout_height="wrap_content"
            android:textSize="30px"
        />
        <TextView 
            android:id="@+id/birthday"
            android:layout_width="130px"
            android:layout_height="wrap_content"
            android:textSize="30px"
        />
    </TableRow>

</TableLayout>

现在我们需进行查询操作,需要返回一共有多少笔数据,修改一下查询的类

package com.example.sqliteproject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class DH10Cursor {
      private static final String TABLENAME="DH10";
      private SQLiteDatabase db =null;
	public DH10Cursor(SQLiteDatabase db) {
		super();
		this.db = db;
	}
    
	public List<Map<String,Object>> find(int currentPage,int lineSize){
        List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
		String sql = "select id,name,birthday from "+TABLENAME+" limit ?,?";
		String args[] = new String[]{String.valueOf((currentPage-1)*lineSize),String.valueOf(currentPage*lineSize)};
		Cursor result = this.db.rawQuery(sql, args);
		for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){
			Map<String,Object> map = new HashMap<String,Object>();
			map.put("id", result.getInt(0));
			map.put("name", result.getString(1));
			map.put("birthday", result.getString(2));
			list.add(map);
		}
		return list;
	}
	
	public int getCount(){
		int count = 0;
		String sql = "select count(id) from "+TABLENAME;
		Cursor result  = this.db.rawQuery(sql, null);
		for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){
			count = result.getInt(0);//取得数据的总笔数
		}
		return count;
	}
}

下面写一下主布局文件,这个比较简单,直接放一个线性布局管理器就可以了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mainlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    

</LinearLayout>

现在只剩下Activity

package com.example.sqliteproject;

import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

import com.example.sqliteopenhelper.MySQLiteOpenHelper;

public class SQLiteActivity extends Activity {
	MySQLiteOpenHelper helper=null;
	ListView listView = null;
	LinearLayout mainLayout = null;
	int currentPage = 1;
	int lineSize = 5;
	int count = 0;
	int pageSize = 1;//总页数
	int lastItem = 0;//保存最后一个记录点
	SimpleAdapter adapter = null;
	TextView tv = null;//底部信息
	LinearLayout loadLayout = null;//底部提示框布局
	List<Map<String,Object>> list = null;
	LayoutParams lp= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
	@Override
	protected void onCreate(Bundle savedInstanceState) {
	       super.onCreate(savedInstanceState);  
	       super.setContentView(R.layout.listview_main);
	       this.mainLayout=(LinearLayout) super.findViewById(R.id.mainlayout);
	       this.loadLayout=new LinearLayout(this);
	       this.tv = new TextView(this);
	       tv.setText("数据加载中,请稍后。。。");
	       tv.setGravity(Gravity.CENTER);
	       tv.setTextSize(30);
	       loadLayout.addView(this.tv,this.lp);
	       loadLayout.setGravity(Gravity.CENTER);
	       this.showAllData();
	}

    private void showAllData(){
    	this.helper = new MySQLiteOpenHelper(this);
    	this.listView = new ListView(this);
    	DH10Cursor cursor = new DH10Cursor(this.helper.getWritableDatabase());//获得一个查询操作对象
    	this.count = cursor.getCount();//取得总数据笔数
    	this.list = cursor.find(currentPage, lineSize);
    	this.adapter = new SimpleAdapter(this, list, R.layout.listview_item_layout, 
    			new String[]{"id","name","birthday"},new int[]{R.id.id,R.id.name,R.id.birthday});//实例化适配器对象
    	SQLiteActivity.this.listView.addFooterView(SQLiteActivity.this.loadLayout);
    	this.listView.setAdapter(adapter);
    	this.listView.setOnScrollListener(new OnScrollListener() {
			
			@Override
			public void onScrollStateChanged(AbsListView view, int scrollState) {
				if(SQLiteActivity.this.lastItem==SQLiteActivity.this.adapter.getCount()//表示当前记录已经在最底部
						&&SQLiteActivity.this.currentPage<SQLiteActivity.this.pageSize//当前页要小于总页数
						&&scrollState==OnScrollListener.SCROLL_STATE_IDLE//屏幕不再滚动
						){
					SQLiteActivity.this.currentPage++;
					SQLiteActivity.this.listView.setSelection(SQLiteActivity.this.lastItem);//设置显示位置
					SQLiteActivity.this.listView.addFooterView(SQLiteActivity.this.loadLayout);
					SQLiteActivity.this.appendData();
				}
				
			}
			
			@Override
			public void onScroll(AbsListView view, int firstVisibleItem,
					int visibleItemCount, int totalItemCount) {
				SQLiteActivity.this.lastItem = firstVisibleItem+visibleItemCount-1;
			}
		});
    	mainLayout.addView(this.listView);
    	if(this.count%this.lineSize==0){
    		this.pageSize = this.count/this.lineSize;
    	}else{
    		this.pageSize = this.count/this.lineSize+1;
    	}
    }
    private void appendData(){//更新数据方法
    	DH10Cursor cursor = new DH10Cursor(this.helper.getWritableDatabase());
    	List<Map<String,Object>> newData = cursor.find(currentPage, lineSize);
    	this.list.addAll(newData);
    	this.adapter.notifyDataSetChanged();//适配器重新加载集合数据
    }
}

以上就是整个实现下滑屏幕实现分页加载数据的程序。

事务的处理是针对数据库而已,以后的开发当中,只要针对增删改,都需要用事务进行处理。

public void insert(String name,String birthday){
		SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象
		db.beginTransaction();//开启事务
		try{
		ContentValues cv = new ContentValues();
		cv.put("name", name);
		cv.put("birthday", birthday);
		db.insert(TABLENAME, null, cv);//进行新增操作
		db.setTransactionSuccessful();//正确执行,否则回滚
		}catch(Exception e){
			db.endTransaction();//事务关闭
			db.close();
		}
		
	}

1.3 小结

(1)SQLite数据库是一个专门用于嵌入式设备的数据库;

(2)SQLite支持SQL语句的操作;

(3)可以使用SQLiteOpenHelper类完成数据库的操作;

(4)所有的查询数据使用Cursor进行接收;

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

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

相关文章

RabbitMQ:hello结构

1.在Linux环境上面装入rabbitMQ doker-compose.yml version: "3.1" services:rabbitmq:image: daocloud.io/library/rabbitmq:managementrestart: alwayscontainer_name: rabbitmqports:- 6786:5672- 16786:15672volumes:- ./data:/var/lib/rabbitmq doker-compos…

Vue框架--Vue中的样式绑定

1.Vue绑定class样式属性(内部样式) 这里我们介绍三种Vue关于绑定class属性的操作。 ①.字符串写法:适用于:样式的类名不确定,需要动态指定 ②.数组写法:适用于:要绑定的样式个数不确定、名字也不确定 ③.对象写法:

vscode 调试debug rust代码的时候,中文乱码的解决办法

上次也是同样的问题&#xff0c;解决了。今天又遇到&#xff0c;我还以为是项目代码用了什么高深的地方&#xff0c;其实用chcp 65001&#xff0c;都可以解决。 一种解决方法是&#xff1a; 但建议不要用这种方法&#xff0c;因为会引起其他软件不能用&#xff08;或者出问题…

山西电力市场日前价格预测【2023-09-07】

日前价格预测 预测明日&#xff08;2023-09-07&#xff09;山西电力市场全天平均日前电价为331.72元/MWh。其中&#xff0c;最高日前电价为461.61元/MWh&#xff0c;预计出现在19: 30。最低日前电价为254.50元/MWh&#xff0c;预计出现在12: 45。 价差方向预测 1&#xff1a; 实…

stm32同芯片但不同flash工程更换Device出现报错

目录 1. 问题描述2. 解决方案 1. 问题描述 stm32同芯片但不同flash工程更换Device出现报错 2. 解决方案 更换Device&#xff0c;我是从ZE换为C8&#xff1a; 把这个从HD更换为MD 解决&#xff01;

3D点云处理:Opencv Pcl实现深度图转点云(附源码)

文章目录 0. 测试效果1. 代码实现文章目录:3D视觉个人学习目录微信:dhlddxB站: Non-Stop_0. 测试效果 处理结果1. 代码实现 文章中提供的深度图像,深度图像一般以.tiff和.png保存,可以通过Opencv中的

Echarts图表跟随父容器的变化自适应

如果页面中有多个图表 隐藏/展开左边侧边栏echarts图表自适应 <div class"line"><div class"title">制冷站关键参数</div><div id"chartLine1" style"width: 100%;height:85%;"></div></div><…

生成树STP中的概念

在数据结构中&#xff0c;有一个方法叫做最小生成树。有环的我们常称为图。将图中的环破了&#xff0c;就生成了树。在计算机网络中&#xff0c;生成树的算法叫作 STP&#xff0c;全称 Spanning Tree Protocol。 Root Bridge&#xff0c;也就是根交换机。这个比较容易理解&…

卖家福利!第三方物流兼容亚马逊日本站运输管理功能!

亚马逊日本站发布公告称外部解决方案提供商Redo Bong LLC提供的库存和运输管理应用程序 “maru9”中添加了与亚马逊 “Marketplace Shipping Service”兼容的运输管理功能&#xff0c;以下是公告内容&#xff1a; 外部解决方案提供商Redo B…

怎么解决期权手续贵的问题?

在开通50ETF期权交易权限之前&#xff0c;券商可能会要求您参加相关的培训或考试&#xff0c;以确保您了解ETF期权交易的基本概念和交易规则&#xff0c;特别是期权手续费的问题&#xff0c;在你开之前&#xff0c;需要咨询协商价格&#xff0c;符合你的心理预期再去开通&#…

【LeetCode算法系列题解】第61~65题

CONTENTS LeetCode 61. 旋转链表&#xff08;中等&#xff09;LeetCode 62. 不同路径&#xff08;中等&#xff09;LeetCode 63. 不同路径 II&#xff08;中等&#xff09;LeetCode 64. 最小路径和&#xff08;中等&#xff09;LeetCode 65. 有效数字&#xff08;困难&#xff…

线程中的join()、wait() 和 notify()详解及练习题

一、join() Thread 类提供了 join() 方法&#xff0c;用于等待当前线程所调用的其他线程执行完毕。 1、当一个线程调用另一个线程的 join() 方法时&#xff0c;它会被阻塞&#xff0c;直到被调用的线程执行完毕或达到指定的超时时间。 比如&#xff1a;当主线程main中调用了…

手把手教会如何掌握Swagger

文章目录 前言一、Swagger重要组件及作用二、SpringBoot集成Swagger1.环境准备2.配置Swagger3.配置Swagger扫描接口4.配置API分组5.拓展&#xff1a;其他皮肤 三、常用注解1.接口注解2.方法及参数注解3.实体类注解效果如图&#xff1a; ![在这里插入图片描述](https://img-blog…

面向未来的编程方式,做为开发者,很必要了解一下什么是iVX

面向未来的编程方式&#xff0c;做为开发者&#xff0c;很必要了解一下什么是iVX 一前言二什么是传统低代码平台以及传统平台的局限性和作用1.什么是传统低代码平台2.传统平台的局限性 三为什么程序员和技术管理者不太可能接受“低代码”平台&#xff1f;1.低代码的特征2.为什么…

【C++基础】4. 变量

文章目录 【 1. 变量的定义 】【 2. 变量的声明 】示例 【 3. 左值和右值 】 变量&#xff1a;相当于是程序可操作的数据存储区的名称。在 C 中&#xff0c;有多种变量类型可用于存储不同种类的数据。C 中每个变量都有指定的类型&#xff0c;类型决定了变量存储的大小和布局&am…

Windows server 2012安装IIS的方法

Windows Server 2012是微软公司研发的服务器操作系统&#xff0c;于2012年9月4日发布。 Windows Server 2012可以用于搭建功能强大的网站、应用程序服务器与高度虚拟化的云应用环境&#xff0c;无论是大、中或小型的企业网络&#xff0c;都可以使用Windows Server 2012的管理功…

*** error 65: access violation at 0xFFFFFFF4 : no ‘write‘ permission怎么办

我发现是我的单片机型号设置错了&#xff0c;把debug里面的STM32F103ZET6修改为STM32F103ZE就可以正常运行了

信息检索度量指标(MAP@N, P@N)

我们今天遇到的大多数软件产品都集成了某种形式的搜索功能。我们在谷歌上搜索内容&#xff0c;在YouTube上搜索视频&#xff0c;在亚马逊上搜索产品&#xff0c;在Slack上搜索信息&#xff0c;在Gmail上搜索邮件&#xff0c;在Facebook上搜索人等等。 作为用户&#xff0c;工作…

基于SSM+Vue的网上花店系统

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

【问题总结】 记 一次dockerFile构建报错

写在前面&#xff0c; 其实是一个比较摸不着脑袋的bug&#xff0c;记录一下解决的过程&#xff0c;作为备忘录 问题留档 1、场景描述 在尝试使用dockefile构建一个tomcat镜像&#xff0c;内容如下&#xff0c;构建正常通过&#xff0c;但是容器启动失败 FROM centos:7 MAINT…