Android开发从0开始(ContentProvider与数据)
内容提供者:ContentProvider
为App存取内部数据提供外部接口,让不同应用共享数据。
①在配置里AndroidManifest.xml
<provider
android:name=".UserInfoProvider"
android:authorities="com.example.chapter07_server.provider.UserInfoProvider"
android:enabled="true"
android:exported="true"/>
危险权限表:
运行时动态申请权限Lazy模式:
①检查是否开启指定权限:
public class PermissionUtil {
//检查权限,返回true则已完全启用权限,返回false表示未完全启用权限
public static boolean checkPermission(Activity act,String[] permissions,int requestCode)
{
int check = PackageManager.PERMISSION_GRANTED;
//逐一将各个权限取出判断
for(String permission: permissions){
ContextCompat.checkSelfPermission(act,permission);
check=ContextCompat.checkSelfPermission(act,permission);
if(check!=PackageManager.PERMISSION_GRANTED){break;}
}
//②若有未开启的权限,则请求系统弹窗
if (check!=PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(act,permissions,requestCode);
return false;
}
return true; } }
③判断用户的权限选择结果:
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//判断用户是否授权
switch (requestCode){
case REQUEST_CODE_CONTACTS:
if(PermissionUtil.checkGRant(grantResults)){
Log.d("ning","通讯录权限获取成功");
}else
{
Log.d("ning","获取通讯录读写权限失败");
}
break;
case REQUEST_CODE_SMS:
if (PermissionUtil.checkGRant(grantResults)){
Log.d("ning","收发短信权限获取成功");
}else
{
Log.d("ning","收发短信权限获取失败");
jumpToSetting();
}
break; } }
//跳转带应用设置界面
private void jumpToSetting(){
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package",getPackageName(),null));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
运行时动态申请权限Hunger模式:直接在onCreate中申请所有权限。
ContentResovler基本用法
添加联系人:
public void onClick(View view) {
int id = view.getId();
if (id == R.id.add) {//创建一个联系人对象
Contact contact = new Contact();
contact.name= et_name.getText().toString().trim();
contact.email=et_email.getText().toString().trim();
contact.phone=et_phone.getText().toString().trim();
//方法一,使用ContentResolver多次写入.
addContacts(getContentResolver(),contact);
} else if (id == R.id.find) {
}
}
//往手机通讯录里添加一个联系人
private void addContacts(ContentResolver resolver, Contact contact) {
ContentValues values = new ContentValues();
Uri uri= resolver.insert(ContactsContract.RawContacts.CONTENT_URI,values);
long rawContactId = ContentUris.parseId(uri);
ContentValues name = new ContentValues();
//关联联系人编号
name.put(Contacts.Data.RAW_CONTACT_ID,rawContactId);
//"姓名"数据类型
name.put(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
//联系人的姓名
name.put(Contacts.Data.DATA2,contact.name);
//往提供器添加联系人姓名
resolver.insert(ContactsContract.Data.CONTENT_URI,name);
ContentValues phone = new ContentValues();
//关联联系人编号
phone.put(Contacts.Data.RAW_CONTACT_ID,rawContactId);
//"电话号码"数据类型
phone.put(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
//联系人的电话号码
phone.put(Contacts.Data.DATA2,contact.phone);
phone.put(Contacts.Data.DATA2,CommonDataKinds.phone.TYPE_MOBILE);
//往提供器添加联系人姓名电话号码
resolver.insert(ContactsContract.Data.CONTENT_URI,phone);
ContentValues email = new ContentValues();
//关联联系人编号
email.put(Contacts.Data.RAW_CONTACT_ID,rawContactId);
//"邮箱"数据类型
email.put(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
//联系人的邮箱
email.put(Contacts.Data.DATA2,contact.email);
//往提供器添加联系人邮箱
resolver.insert(ContactsContract.Data.CONTENT_URI,email);
}
批量处理添加联系人:
private void addFullContacts(ContentResolver resolver , Contact contact){
//构建一个插入联系人主记录的内容操作器
ContentProviderOperation op_main=ContentProviderOperation
.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME,null)
.build();
//构建对于姓名的操作
ContentProviderOperation op_name= ContentProviderOperation
.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValueBackReference(Contacts.Data.RAW_CONTACT_ID,0)
.withValue(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(Contacts.Data.DATA2,contact.name)
.build();
//构建对于电话号码操作
ContentProviderOperation phone= ContentProviderOperation
.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValueBackReference(Contacts.Data.RAW_CONTACT_ID,0)
.withValue(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(Contacts.Data.DATA2,contact.phone)
.build();
//构建对于邮箱的操作
ContentProviderOperation email= ContentProviderOperation
.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValueBackReference(Contacts.Data.RAW_CONTACT_ID,0)
.withValue(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(Contacts.Data.DATA2,contact.email)
.build();
//构建列表将三个操作放入
ArrayList<ContentProviderOperation> operations=new ArrayList<>();
operations.add(op_main);
operations.add(op_name);
operations.add(phone);
operations.add(email);
//批处理提交四个操作
try {
resolver.applyBatch(ContactsContract.AUTHORITY,operations);
} catch (OperationApplicationException e) {
throw new RuntimeException(e);
} catch (RemoteException e) {
throw new RuntimeException(e); } }
批量查询联系人:
//查询通讯录信息
@SuppressLint("Range")
private void readPhoneContacts(ContentResolver resolver ) {
Cursor cursor= resolver.query(ContactsContract.RawContacts.CONTENT_URI,new String[]{ContactsContract.RawContacts._ID},null,null,null,null);
while (cursor.moveToNext()){
int rawContactId = cursor.getInt(0);
Uri uri = Uri.parse("content://com.android.contacts/contacts"+rawContactId+"/data");
Cursor dataCursor=resolver.query(uri,new String[]{Contacts.Data.MIMETYPE,Contacts.Data.DATA1,Contacts.Data.DATA2},null,null,null);
Contact contact = new Contact();
while (dataCursor.moveToNext()){
String data1= dataCursor.getString(dataCursor.getColumnIndex(Contacts.Data.DATA1));
String mimeType=dataCursor.getString(dataCursor.getColumnIndex(Contacts.Data.MIMETYPE));
switch (mimeType){
case CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE:
contact.name=data1; break;
case CommonDataKinds.Email.CONTENT_ITEM_TYPE:
contact.Email=data1; break;
case CommonDataKinds.Phone.CONTENT_ITEM_TYPE:
contact.Phone=data1; break;
}
}
dataCursor.close();
}
cursor.close(); }
ContentObserver监听短信:
public class MonitorSmsActivity extends AppCompatActivity {
private SmsGetObserver mObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_monitor_sms);
//指定一个注册内容观察器,一单数据发生变化,就触发OnChange方法
Uri uri = Uri.parse("content://sms");
mObserver = new SmsGetObserver(this);
getContentResolver().registerContentObserver(uri,true,mObserver);
}
protected void onDestroy(){
super.onDestroy();
getContentResolver().unregisterContentObserver(mObserver);
}
private static class SmsGetObserver extends ContentObserver {
private final Context mContext;
public SmsGetObserver(Context context){
super(new Handler(Looper.getMainLooper()));
this.mContext=context; }
public void onChange(boolean selfChange, @Nullable Uri uri){
super.onChange(selfChange,uri);
if(uri==null){return;}
if(uri.toString().contains("content://sms/raw")||uri.toString().equals("content://sms")) {return;}
Cursor cursor = mContext.getContentResolver().query(uri, new String[]{"address", "body", "date"}, null, null, "date DESC");
if(cursor.moveToNext()){
//短信的发送号码
@SuppressLint("Range") String sender=cursor.getString(cursor.getColumnIndex("address"));
@SuppressLint("Range") String content=cursor.getString(cursor.getColumnIndex("body"));
Log.d("ning",String.format("sender:%s,content:%s",sender,content));
}
cursor.close();
}
} }
跳转选择图片:
①创建意图
Intent intent = new Intent(Intent.ACTION_GET_CONTENT );
②设置图片内容类型与跳转
Intent.setType(“image/*”);
mResultLauncher.launch(intent );
FileProvider:
继承于ContentProvider,对第三方应用暴露文件,并授权读写操作的权限。
①首先在AndroidManifest.xml文件中配置
<provider
android:authorities="@string/file_provider"
android:name="androidx.core.content.FileProvider"
android:grantUriPermissions="true">
<!--配置哪些路径是可以通过FileProvider访问-->
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
②其次在对应路径xml的文件夹中的file_paths中写配置文件。
③在代码中对应实现。
访问其他程序中的数据:
①使用现有的内容提供器来读取和操作相应的程序数据
②创建自己的内容提供器给我们程序的数据提供外部访问接口。
Notification通知栏的使用:
Notification notification = new Notification.Builder(this)
.setContentTitle("this is content title") //指定通知栏标题内容
.setContentText("this is content text")//指定通知栏正文内容
.setWhen(System.currentTimeMillis())//创建时间
.setSmallIcon(R.mipmap.ic_launcher) //通知栏小图标
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
.build(); //通知栏大图标
manager.notify(NOTIFICATION_ID, notification); //通道号要提前创建
参数1:通道号 参数2:notification对象
PendingIntent延迟意图:
方法1:getActivity()
方法2:getBroadcast()
方法3:getService()
以上均为三个参数:参1:Context 。参2:一般不用传0。参数3:意图
参数4:确定行为FLAG_ONESHOT,FLAG_NO_CREATE,FLAG_CANCEL,FLAG_UPDATE_CURRENT通常可以填0.
点击后图标消失:
①在后部分调用.setAutoCancel( true )方法
②在onCreate中
NotificationManager manager = (Notif icat ionManager) getSystemService
(NOTIFICATION_ SERVICE) ; //注册管理器
manager . cancel((NOTIFICATION_ID); . //注册取消。
调用摄像头:
①创建File对象,用于存储。
②调用getExternalCacheDir( )方法获取目录。
③做版本适配
④用intent去启动摄像头。
注意调用都有权限注册。
播放音频:
一般使用MediaPlayer类实现,常用方法如下
调用播放视频:
一般使用VideoView类的方法。
数据存储部分:
共享参数-SharedPreferences:轻量级存储工具,Key-Value形式。
使用场景:
①简单且孤立的数据。
②文本形式数据。
③需要持久化存储的数据。
④App个性化配置信息,用户使用App行为信息。
⑤临时片段信息。
getSharedPreferences("config", Context.MODE_PRIVATE);
①然后先ALT+ENTER声明成变量,再Ctrl+ALT+F变全局
private SharedPreferences preferences;
preferences = getSharedPreferences("config", Context.MODE_PRIVATE);
//在下面监听
public void onClick(View view) {
String name = et_name.getText().toString();
String age = et_age.getText().toString();
String height = et_height.getText().toString();
String weight = et_weight.getText().toString();
//获取编辑器
SharedPreferences.Editor editor = preferences.edit();
editor.putString("name",name);
editor.putInt("age", Integer.parseInt(age));
editor.putFloat("height",Float.parseFloat(height));
editor.putFloat("weight",Float.parseFloat(weight));
editor.putBoolean("married",gr_married.isChecked());
editor.commit();
}
②重新再取数据:(通过键值对取)
String name= preferences.getString("name","");
SQLite
(1) 数据定义语言:
CREATE TABLE IF NOT EXISTS 表名(
字段A PRIMARY KEY
字段B,
字段C
)
支持类型:
NULL:表示空值。
INTEGER:表示整数,可以存储整数值。
REAL:表示浮点数,可以存储浮点数值。
TEXT:表示文本,可以存储字符串。
BLOB:表示二进制数据,可以存储任意二进制数据。
(2)删除表格:
DROP TABLE IF EXISTS user_info
(3)修改表格:
ALTER TABLE user_info ADD COLUMN phone VARCHAR;
(只支持增加字段,不支持修改,删除字段)添加多列就分多次。
(4)数据操作语言与其他数据库相似
- SQLite Database 数据库管理器:
1,管理类:
OpenDatabase():打开指定路径数据库。
isOpen():判断数据库是否已经打开。
Close():关闭数据库。
getVersion():获取版本。
SetVersion():设置数据库版本。
2,事务类:
beginTransaction:开始事物。
SetTransactionSuccessful:设置事务的成功标志.
endTransaction:结束事务。
创建数据库,删除数据库:
①首先在全局生命这个数据库名
private String mDataBaseName;
mDataBaseName = getFilesDir() + "/test.db";
public void onClick(View view) {
int id = view.getId();
if (id == R.id.btn_database_create) {
//打开数据库,参数1:数据库名地址+名字,参数2:打开模式,参数3:游标
SQLiteDatabase db = openOrCreateDatabase(mDataBaseName, Context.MODE_PRIVATE, null);
//输出化语言:
String desc = String.format("数据库%s创建%s", db.getPath(), (db != null) ? "成功" : "失败");
tv_database.setText(desc);}
else if (id == R.id.btn_database_delete) {
//删除数据库
boolean result = deleteDatabase(mDataBaseName);
String desc_fail = String.format("数据库%s删除%s", mDataBaseName, result ? "成功" : "失败");
tv_database.setText(desc_fail); } }
数据库所在路径:data->data->包名->file
页面与数据库交互:SQLiteOpenhelper
两个抽象方法: onCreate ( ), onUpgrade ( )
两个重要实例方法getReadableDatabase( ), getWritableDatabase( )。均可创建或打开数据库。
(6)事务管理:(一致性,原子性)
beginTransaction:开始事务.
setTransactionSuccessful:设置事务的成功标志.
endTransaction:结束事务.
若事务失败泽会回滚操作,保证原子性。
- 外部存储空间
定义部分
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.Buffer;
public class FileUtil {
//把字符串保存到指定路径
public static void saveText(String path,String txt){
BufferedWriter os =null; //创建一个os
try {os = new BufferedWriter(new FileWriter(path)); //new一个对象,其中包含指定路径
os.write(txt); //将txt 写入该路径
}catch (Exception e){
e.printStackTrace();
}finally {
if (os!=null)
{
try {
os.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
//从指定路径读取内容字符串
public static String openText(String path){
BufferedReader is=null;
StringBuilder sb =new StringBuilder();
try {
is =new BufferedReader(new FileReader(path));
String line = null;
while ((line=is.readLine())!=null){
sb.append(line);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (is!=null)
{
try {
is.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
return sb.toString();
}
}
引用部分:
//外部存储的私有空间写入
String directory = null; //创建一个字符串
String fileName = System.currentTimeMillis()+".txt"; //创建一个当前时间的文件名
directory = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(); //获取路径
path =directory + File.separatorChar+fileName; //构建完整路径
FileUtil.saveText(path,sb.toString()); //进行保存
ToastUtil.show(this,"保存成功");
//外部存储的私有空间读出
tv_txt.setText(FileUtil.openText(path))
外部存储公有空间:还要手机获取权限
directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();
(7)存储卡上读写图片文件
BitmapFactory工具用于读取各种来源的图片:相关方法如下:
decodeResource:该方法可从资源文件中读取图片信息。
DecodeFile:该方法可将指定路径的图片读取到Bitmap对象。
DecodeStream:该方法从输入流中读取位图数据。
①定义触发保存事件
public void onClick(View view) {
int id = view.getId();
if (id == R.id.btn_save) {
String fileName = System.currentTimeMillis() + ".jpeg";
//获取当前App的私有下载目录
path = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + File.separatorChar + fileName;
//从指定资源文件获取位图像对象
Bitmap b1 = BitmapFactory.decodeResource(getResources(), R.drawable.ting1);
//将位图对象保存下来
FileUtil.saveImage(path, b1);
ToastUtil.show(this, "保存成功");
} else if (id == R.id.btn_read) {
Bitmap b2 = FileUtil.openImage(path);
iv_content.setImageBitmap(b2);
} }
②对应保存
//把位图数据保存到指定路径的图片文件
public static void saveImage(String path, Bitmap b1) {
FileOutputStream fos = null;
try{
fos=new FileOutputStream(path);
//把位图数据压缩到文件流中
b1.compress(Bitmap.CompressFormat.JPEG,100,fos);}
catch (Exception e){ e.printStackTrace(); }finally {
//关闭输入输出流
if(fos!=null){
try { fos.close(); }catch (IOException e){
e.printStackTrace(); } } } }
③读取相应位图
//从指定路径读取位图数据
public static Bitmap openImage(String path) {
Bitmap bitmap=null;
FileInputStream fis=null;
try {
fis =new FileInputStream(path);
bitmap = BitmapFactory.decodeStream(fis);
}catch (Exception e){
e.printStackTrace();
}finally {
if (fis!=null){
try {
fis.close();
}catch (IOException e)
{
e.printStackTrace();
} } } return bitmap; }
(8)Application生命周期
在App运行过程中有且仅有一个Application对象,贯穿生命周期。
public class MyApplication extends Application {
//在APP启动时调用
@Override
public void onCreate() {
super.onCreate();
Log.d("ning","onCreate");
}
//APP终止(在真实的产品不会回调)
@Override
public void onTerminate() {
super.onTerminate();
Log.d("ning","onTerminate");
}
//配置改变时调用
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
}
- Application全局变量
适用于会频繁读取的信息,如用户名,手机号。
不方便由意图传输的数据,例如位图对象,非字符串类型。
容易因频繁分配内存导致的内存泄漏的对象,Handler等。可以采用单例模式。
操作:
- private static MyApplication mApp; //定义一个私有静态的实例MyApplication名为app
- public static MyApplication getInstance(){ return mApp; }//获取单例,返回mApp
- public void onCreate() {
super.onCreate(); mApp = this; }//在oncreate里实例化,将this指针地址给mApp
④在外部再调用MyApplication.getInstance();
- JetPackRoom:
Room框架通过注解技术简化数据库操作。
①在build.gradle的dependencies中配置
implementation 'androidx.room:room-runtime:2.2.5'// 导入 Room 依赖库
annotationProcessor 'androidx.room:room-compiler:2.2.5'// 导入注解处理器 ( Java )
②编写一个表对应的实体类Bookinfo
package com.example.myapplication.enity;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity
public class Bookinfo {
@PrimaryKey(autoGenerate = true) //自动增长
private int id;
private String name;
private String author;
private String press;
private double price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getPress() {
return press;
}
public void setPress(String press) {
this.press = press;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Bookinfo{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
", press='" + press + '\'' +
", price=" + price +
'}';
}
}
③编写一个表对应的持久化类BookDao的接口。会自动生产类。
package com.example.myapplication.dao;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import com.example.myapplication.enity.Bookinfo;
import java.util.List;
@Dao
public interface BookDao {
@Insert
void insert(Bookinfo... book);
@Delete
void delete(Bookinfo... book);
@Query("DELETE FROM Bookinfo")
void deleteAll();
@Update
int update(Bookinfo... book);
@Query("SELECT * FROM bookinfo ")
List<Bookinfo>queryAll();
@Query("SELECT * FROM bookinfo WHERE name = :name ORDER BY id DESC limit 1")
Bookinfo queryByName(String name);
}
④创建一个抽象类:BookDatabase
@Database(entities = {Bookinfo.class},version = 1,exportSchema = true)
public abstract class BookDatabase extends RoomDatabase {
//获取该数据库中某张表的持久化对象
public abstract BookDao bookDao(); }
⑤在自定义的Application类中声明书籍数据库的唯一实例。
public class RoomWriteActivity extends AppCompatActivity implements View.OnClickListener {
private EditText shuming;
private EditText zuozhe;
private EditText chubanshe;
private EditText jiage;
private BookDatabase bookDB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_room_write);
shuming = findViewById(R.id.shuming);
zuozhe = findViewById(R.id.zuozhe);
chubanshe = findViewById(R.id.chubanshe);
jiage = findViewById(R.id.jiage);
findViewById(R.id.btn_chaxun).setOnClickListener(this);
findViewById(R.id.btn_shanchu).setOnClickListener(this);
findViewById(R.id.btn_tianjia).setOnClickListener(this);
findViewById(R.id.btn_xiugai).setOnClickListener(this);
//从App实例中获取唯一的书籍持续化对象
bookDB = MyApplication.getInstance().getBookDB();
}
@Override
public void onClick(View view) {
String name=shuming.getText().toString();
String author=zuozhe.getText().toString();
String press=chubanshe.getText().toString();
String price=jiage.getText().toString();
int id = view.getId();
if (id == R.id.btn_tianjia) {
Bookinfo b1 = new Bookinfo();
b1.setName(name);
b1.setAuthor(author);
b1.setPress(press);
b1.setPrice(Double.parseDouble(price));
bookDao.insert(b1);
} else if (id == R.id.btn_xiugai) {
List<Bookinfo> list= bookDao.queryAll();
for(Bookinfo b:list){
Log.d("ning",b.toString());
}
} else if (id == R.id.btn_shanchu) {
} else if (id == R.id.btn_chaxun) {
}
}
}
相关文章:

Android开发从0开始(ContentProvider与数据)
内容提供者:ContentProvider 为App存取内部数据提供外部接口,让不同应用共享数据。 ①在配置里AndroidManifest.xml <provider android:name".UserInfoProvider" android:authorities"com.example.chapter07_server.provider.U…...

STM32_6(TIM)
TIM定时器(第一部分) TIM(Timer)定时器定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时不仅…...

Linux中flask项目开启https访问
1.下载阿里云免费证书 2.项目添加https配置 3.服务器开启https访问 3.1 重新安装OpenSSL 3.2.重新安装Python 上一次已经讲过Linux安装部署Python: Linux安装Python3.10与部署flask项目实战详细记录,今天记录一下Python项目如何支持https访问…...

Kubernetes 离线部署 Spinnaker
离线部署 Spinnaker 离线部署 spinnaker 需要提前准备以下依赖项 halyard 安装工具:该hal命令的apt源地址https://us-apt.pkg.dev/projects/spinnaker-community位于国外halyard boms物料清单:Spinnaker 将其halyard boms配置存储在公共谷歌云存储 ( g…...

TypeScript 学习笔记 第三部分 贪吃蛇游戏
尚硅谷TypeScript教程(李立超老师TS新课) 1. 创建开发环境 创建工程,使用学习笔记的第二部分安装css部分 npm i -D less less-loader css-loader style-loader对css部分处理,能够运行在低版本浏览器 npm i -D postcss postcss…...
【spring(一)】核心容器总结
🌈键盘敲烂,年薪30万🌈 目录 IOC 配置bean对象: DI 注入bean对象 ①.setter方法注入 ②.构造器注入 Bean的实例化 1.setter方法注入(重点) 2.静态工厂(了解) 3.实例工厂(了解࿰…...

易点易动固定资产管理系统:实现全面的固定资产采购管理
在现代企业中,固定资产采购管理是一项关键的任务。为了确保企业的正常运营和发展,有效管理和控制固定资产采购过程至关重要。易点易动固定资产管理系统为企业提供了一种全面的解决方案,整合了从采购需求、采购计划、询比价、采购合同到采购执…...

力扣:178. 分数排名(Python3)
题目: 表: Scores ---------------------- | Column Name | Type | ---------------------- | id | int | | score | decimal | ---------------------- 在 SQL 中,id 是该表的主键。 该表的每一行都包含了一场比赛的分数。Score …...

raid磁盘阵列
在单机时代,采用单块磁盘进行数据存储和读写的方式,由于寻址和读写的时间消耗,导致I/O性能非常低,且存储容量还会受到限制。另外,单块磁盘极其容易出现物理故障,经常导致数据的丢失。此时,RAID技…...
SpringBoot学习笔记-实现微服务:匹配系统(上)
笔记内容转载自 AcWing 的 SpringBoot 框架课讲义,课程链接:AcWing SpringBoot 框架课。 CONTENTS 1. 配置WebSocket2. 前后端WebSocket通信2.1 WS通信的建立2.2 加入JWT验证 3. 前后端匹配业务3.1 实现前端页面3.2 实现前后端交互逻辑3.3 同步游戏地图 …...

重磅!全球首个“绿色黑灯工厂”落户中国,竟然是这家企业……
作者:叶蓁 “52”、“白加黑”、“无人看守作业”,这是九牧“绿色黑灯工厂”的几大关键词。 九牧绿色黑灯工厂不仅是单体产量最大的工厂,也是全球首个入选的“绿色黑灯工厂”。 11月17日,中国节能协会授予九牧5G智能马桶工厂全球…...
go语言学习-异常处理
1、异常场景 网络故障硬件故障组件故障输入错误逻辑错误链路调度错误 2、异常处理方式 # python或者java异常处理 try 可能出现的错误 catch对错误进行处理 xxx,err : 代码 if err ! nil {代码出现错误,需要做处理 }3、自定义错误 有两种方法:1、通过…...
如何使用 JavaScript 实现图片上传并转换为 LaTeX 公式
在本教程中,我们将学习如何使用 JavaScript 创建一个上传图片的功能,并将所选图片转换为 LaTeX 公式。我们将使用 FileReader 对象来读取图片并将其转换为 Base64 格式,然后利用 img2latex API 将其转换为 LaTeX 公式。 1. HTML 结构 首先&…...
深刻理解MySQL8游标处理中not found
深刻理解MySQL8游标处理中not found 最近使用MySQL的游标,在fetch循环过程中,程序总是提前退出 ,百思不得其解,经过测试,原来是对于游标处理中not found的定义理解有误,默认是视同Oracle的游标not found定…...

甄知燕千云与SAP、EBS、TC、NS等应用深度集成,智能提单一键畅通,效能一键提升
当今全球化时代下,全球商业环境面临前所未有的机遇和挑战,企业需要持续的业务变革、组织优化来进行降本增效,企业管理软件已成为中小企业、大型企业数字化转型不可或缺的管理工具,企业内管理软件系统也越来越多。 为了适应当前企业…...

第99步 深度学习图像目标检测:SSDlite建模
基于WIN10的64位系统演示 一、写在前面 本期,我们继续学习深度学习图像目标检测系列,SSD(Single Shot MultiBox Detector)模型的后续版本,SSDlite模型。 二、SSDlite简介 SSDLite 是 SSD 模型的一个变种,…...

用EasyAVFilter将网络文件或者本地文件推送RTMP出去的时候发现CPU占用好高,用的也是vcodec copy呀,什么原因?
最近同事在用EasyAVFilter集成在EasyDarwin中做视频拉流转推RTMP流的功能的时候,发现怎么做CPU占用都会很高,但是视频没有调用转码,vcodec用的就是copy,这是什么原因呢? 我们用在线的RTSP流就不会出现这种情况&#x…...

Vatee万腾科技的独特力量:Vatee数字时代创新的新视野
在数字化时代的浪潮中,Vatee万腾科技以其独特而强大的创新力量,为整个行业描绘了一幅崭新的视野。这不仅是一场科技创新的冒险,更是对未来数字时代发展方向的领先探索。 Vatee万腾将创新视为数字时代发展的引擎,成为推动行业向前的…...

【JavaSE】基础笔记 - 异常(Exception)
目录 1、异常的概念和体系结构 1.1、异常的概念 1.2、 异常的体系结构 1.3 异常的分类 2、异常的处理 2.1、防御式编程 2.2、异常的抛出 2.3、异常的捕获 2.3.1、异常声明throws 2.3.2、try-catch捕获并处理 3、自定义异常类 1、异常的概念和体系结构 1.1、异常的…...

QTableWidget——编辑单元格
文章目录 前言熟悉QTableWiget,通过实现单元格的合并、拆分、通过编辑界面实现表格内容及属性的配置、实现表格的粘贴复制功能熟悉QTableWiget的属性 一、[单元格的合并、拆分](https://blog.csdn.net/qq_15672897/article/details/134476530?spm1001.2014.3001.55…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...