jsoup搭配bmob云数据库环境小项目(kotlin)

说明:jsoup就是爬虫框架,bmob就是云端数据库,本项目两者一起使用,巧合是都是大三时查看到的,之前都是简单用用,正好有最近空闲时间写一写,本项目是kotlin代码,代码量可以进一步完善。
项目预览:
在这里插入图片描述

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

项目截图目录:
在这里插入图片描述

主要代码如下:
build.gradle依赖:
//bmob需要云数据库
implementation ‘cn.bmob.android:bmob-sdk:3.7.8’
implementation “io.reactivex.rxjava2:rxjava:2.2.8”
implementation ‘io.reactivex.rxjava2:rxandroid:2.1.1’
implementation ‘com.squareup.okhttp3:okhttp:3.14.1’
implementation ‘com.squareup.okio:okio:2.2.2’
implementation ‘com.google.code.gson:gson:2.8.5’

//协程使用
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"

//2.0.5  AndroidX版本、支持ViewPager2
implementation 'com.github.Vincent7Wong:EasyNavigation:1.5.0'

//轮播图
implementation 'cn.bingoogolapple:bga-banner:3.0.0@aar'

//图片加载框架
implementation 'com.facebook.fresco:fresco:2.0.0'

//eventbus通信
implementation 'org.greenrobot:eventbus:3.1.1'

MyApplication.kt:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
//Bmob注册
Bmob.initialize(this, “app id”)

    //注册加载fresco图片框架
    Fresco.initialize(this);
}

}
MainActivity.kt:
class MainActivity : AppCompatActivity() {

private val tabText = arrayOf("首页","个人")

private val noramlIcon = intArrayOf(
    R.drawable.index,
    R.drawable.personal
)

private val selectIcon = intArrayOf(
    R.drawable.index1,
    R.drawable.personal1
)

private val fragments = ArrayList<Fragment>()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    //去除导航栏 隐藏ActionBar
    supportActionBar!!.hide()
    //全屏
    getWindow().setFlags(
        WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView(R.layout.activity_main)
    fragments.add(HomeFragment())
    fragments.add(UserFragment())


    navigationBar.titleItems(tabText)
        .normalIconItems(noramlIcon)
        .selectIconItems(selectIcon)
        .fragmentList(fragments)
        .setOnTabClickListener(object : EasyNavigationBar.OnTabClickListener{
            override fun onTabSelectEvent(view: View?, position: Int): Boolean = false
            override fun onTabReSelectEvent(view: View?, position: Int): Boolean = false

        })
        .fragmentManager(supportFragmentManager)
        .canScroll(true)
        .build();
}



/**
 * tosat吐司方法
 */
fun Any.toast(context: Context, duration: Int = Toast.LENGTH_SHORT): Toast {
    return Toast.makeText(context, this.toString(), duration).apply { show() }
}

override fun onDestroy() {
    super.onDestroy()
    fragments!!.clear()
}

}
activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>


<com.next.easynavigation.view.EasyNavigationBar
android:id=“@+id/navigationBar”
android:layout_width=“match_parent”
android:layout_height=“match_parent”>

</com.next.easynavigation.view.EasyNavigationBar>
HomeFragment.kt: class HomeFragment : Fragment() { private val listData = ArrayList() //标题列表 private val listTitleData = ArrayList() //连接地址 private var listTitleDataUrl = ArrayList()
val url : String = "http://www.mee.gov.cn/"

/**
 * 全局view变量
 */
private lateinit var loadingDialog: LoadingDialog



/**
 * 初始化布局
 */
override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return inflater.inflate(R.layout.home_fragment, container, false)
}

/**
 * 初始化布局后操作
 */
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    loadingDialog = LoadingDialog(activity)
    loadingDialog.show()
    loadingDialog.setText("加载...")
    initBanner()
    initRv()



}

/**
 * jsoup爬虫 轮播图
 */
fun initBanner(){
    //异步线程
    Thread(object :Runnable{
        override fun run() {
            val document : Document;
            try {
                document = Jsoup.connect(url).get()
                val sorllImg   = document.getElementsByClass("bd").get(0)
                    .getElementsByTag("ul")
                    .select("li").select("img")

                for (item in sorllImg){
                    //attr 获取某个元素值
                    listData.add(url + item.attr("src").substring(2))
                }




                Log.e("Main","爬虫jsoup成功:"+ document)

// (“爬虫jsoup成功:”+ document).toast(this@MainActivity)
activity!!.runOnUiThread {
// (“爬虫jsoup成功:”+ listData.get(0)).toast(activity!!)

                    banner_content.setAdapter(BGABanner.Adapter<CardView,
                            String?> { banner,
                             itemView,
                              model,
                              position ->
                        val simpleDraweeView: SimpleDraweeView =
                            itemView.findViewById(R.id.sdv_item_fresco_content)
                        simpleDraweeView.setImageURI(Uri.parse(model))
                    })
                    /**
                     * 设置是否开启自动轮播,需要在 setData 方法之前调用,并且调了该方法后必须再调用一次 setData 方法
                     * 例如根据图片当图片数量大于 1 时开启自动轮播,等于 1 时不开启自动轮播
                     */
                    banner_content.setAutoPlayAble(listData.size > 1)

                    banner_content.setData(R.layout.item_fresco, listData, null)

                }

            }catch (e: IOException){
                e.printStackTrace()
            }


        }

    }).start()
}

/**
 * 标题
 */
private fun initRv() {

    //异步线程
    Thread(object :Runnable{
        override fun run() {
            val document : Document;

            try {
                document = Jsoup.connect(url).get()
                val sorllImg   = document.getElementsByClass("yaowenlunboUl").get(0)
                        .getElementsByTag("ul")
                        .select("li").select("a").select("div")

                listTitleDataUrl.addAll(document.getElementsByClass("yaowenlunboUl").get(0)
                        .getElementsByTag("ul")
                        .select("li").select("a").eachAttr("href"))


                //循环取值
                for (index in 0 until sorllImg.size){
                    //attr 获取某个元素值 .getElementsByClass("lunboUlWen lunboUlWen" + (index + 1))
                    listTitleData.add(sorllImg[index].childNode(0).toString().trim())

                }



                Log.e("Main","爬虫jsoup成功:"+ document)


                activity!!.runOnUiThread {
                    val gridLayout = GridLayoutManager(activity,2)
                    rv_home.layoutManager = gridLayout
                    val titleAdapter = TitleAdapter(listTitleData)
                    rv_home.adapter = titleAdapter
                    titleAdapter!!.setOnKotlinItemClickListener(object :
                            TitleAdapter.IKotlinItemClickListener{
                        override fun onItemClickListener(position: Int) {

                            var intent = Intent()
                            val bundle = Bundle()
                            bundle.putString("url",url + listTitleDataUrl[position])
                            intent.setClass(activity!!,
                                    WebViewActivity().javaClass)
                            intent.putExtras(bundle)
                            activity!!.startActivity(intent)

                        }

                    })

                    loadingDialog.dismiss()

                }

            }catch (e: IOException){
                e.printStackTrace()
            }


        }

    }).start()
}

/**
 * tosat吐司方法
 */
fun Any.toast(context: Context, duration: Int = Toast.LENGTH_SHORT): Toast {
    return Toast.makeText(context, this.toString(), duration).apply { show() }
}

override fun onDetach() {
    listData.clear()
    super.onDetach()

}
home_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>

<cn.bingoogolapple.bgabanner.BGABanner
    android:id="@+id/banner_content"
    style="@style/BannerDefaultStyle"
    app:banner_pageChangeDuration="1000"
    app:banner_pointAutoPlayAble="false"
    app:banner_pointContainerBackground="@android:color/transparent"
    app:banner_pointDrawable="@drawable/bga_banner_selector_point_hollow"
    app:banner_pointTopBottomMargin="15dp"
    app:banner_transitionEffect="alpha" />
<androidx.recyclerview.widget.RecyclerView
    android:paddingTop="10dp"
    android:id="@+id/rv_home"
    android:scrollbars="none"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
UserFragment.kt:

class UserFragment: Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.user_fragment, container, false)
}
/**
* 初始化布局后操作
*/
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bt_logout.visibility = View.GONE
tv_login.setOnClickListener {
var intent = Intent()
intent.setClass(this.activity!!,
LoginActivity().javaClass)
startActivity(intent)
}
bt_logout.setOnClickListener {
bt_logout.visibility = View.GONE
tv_login.text = “请先登录”
tv_login.isEnabled = true

    }

    cl_about.setOnClickListener {
        //跳转关于
        activity!!.startActivity(Intent().setClass(this.activity!!,AboutActivity::class.java))
    }
    //注册eventbus
    EventBus.getDefault().register(this)
}

@Subscribe
 fun setUser(event: UserEvent){
    bt_logout.visibility = View.VISIBLE
    tv_login.text = event.name
    tv_login.isEnabled = false
}

override fun onDetach() {
    super.onDetach()
    //取消eventbus
    EventBus.getDefault().unregister(this);
}

}

user_fragment.xml:

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=“match_parent”
android:layout_height=“120dp”>


</androidx.constraintlayout.widget.ConstraintLayout>



<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/cl_about"
    android:background="@color/white"
    android:layout_width="match_parent"
    android:layout_height="45dp">
    <ImageView
        android:src="@drawable/ic_launcher_background"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_marginRight="10dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="parent"
        app:layout_constraintTop_toBottomOf="parent"/>
    <TextView
        android:gravity="center_vertical"
        android:text="关于"
        android:textSize="15sp"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        tools:ignore="MissingConstraints" />

</androidx.constraintlayout.widget.ConstraintLayout>
<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="#A48F8F"

/>

<Button
    android:layout_marginTop="80dp"
    android:id="@+id/bt_logout"
    android:text="退出登录"
    android:layout_gravity="center"
    android:layout_marginStart="20dp"
    android:layout_marginEnd="20dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>
User.kt: /** * 用户数据库 */ class User : BmobObject() { var username:String ?= null var password:String ?= null

}
TitleAdapter.kt:
class TitleAdapter(private val titleList: ArrayList) :
RecyclerView.Adapter<TitleAdapter.TitleHolder> (){
private var itemClickListener: IKotlinItemClickListener?= null

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TitleHolder
= TitleHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_title,
    parent,false))

override fun getItemCount(): Int = titleList.size

override fun onBindViewHolder(holder: TitleHolder, position: Int) {
    //设置值
   holder.tv_title.text = titleList[position]
    holder.tv_title.setOnClickListener {
        itemClickListener!!.onItemClickListener(position)
    }
}
//TitleHolder(itemView: View) 构造方法
class TitleHolder(itemView: View):RecyclerView.ViewHolder(itemView){
    val tv_title: TextView = itemView.findViewById(R.id.tv_title)

}

// 提供set方法
fun setOnKotlinItemClickListener(itemClickListener: IKotlinItemClickListener) {
    this.itemClickListener = itemClickListener
}

//自定义接口
interface IKotlinItemClickListener {
    fun onItemClickListener(position: Int)
}

}
item_title.kt:

<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:tools=“http://schemas.android.com/tools”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:layout_marginStart=“5dp”
android:layout_marginEnd=“5dp”
android:layout_marginBottom=“5dp”
android:background=“@color/white”
xmlns:app=“http://schemas.android.com/apk/res-auto”>

</androidx.constraintlayout.widget.ConstraintLayout>

LoginActivity.kt:
class LoginActivity: AppCompatActivity(), View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//去除导航栏 隐藏ActionBar
supportActionBar!!.hide()
//全屏
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_login)

    tv_login.setOnClickListener(this)

}

override fun onClick(view: View?) {
    if (view!!.id == R.id.tv_login){
        if (et_user.text.isEmpty()){
            ToastUtil.toast(
                this,
                "用户名不能为空"
            )
        }else if (et_password.text.isEmpty()){
            ToastUtil.toast(this, "密码不能为空")
        }else{
            query(et_user.text.toString(),et_password.text.toString())
        }

    }
}

/**
 * 查询
 */
fun query(user: String,password : String){
    //是否存在 数量
    val sql = "select count(*) from User where username = '"+ user +
            "'and password = '" + password + "'"
    val bmobQuery = BmobQuery<User>();
    //条件查询
    bmobQuery.setSQL(sql)
    //没有缓存设置

// bmobQuery.cachePolicy = BmobQuery.CachePolicy.NETWORK_ELSE_CACHE;
bmobQuery.doSQLQuery(object :SQLQueryListener(){
override fun done(result: BmobQueryResult?, e: BmobException?) {
if (e == null){
if (result!!.count != 0){
ToastUtil.toast(
this@LoginActivity,
“登录成功”
)
EventBus.getDefault().post(
UserEvent(
user
)
);
finish()
}else{
ToastUtil.toast(
this@LoginActivity,
“该用户不存在或密码错误”
)
}

           }else{
               ToastUtil.toast(
                   this@LoginActivity,
                   "查询失败"
               )
           }
        }

    })


}

}
activity_login.xml

<?xml version="1.0" encoding="utf-8"?>

<ImageView
    android:layout_gravity="center"
    android:src="@drawable/ic_launcher_background"
    android:layout_width="200dp"
    android:layout_height="150dp"/>

<EditText
    android:id="@+id/et_user"
    android:layout_marginTop="50dp"
    android:theme="@style/EditTextBG"
    android:maxLines="1"
    android:hint="请输入用户名"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

<EditText
    android:id="@+id/et_password"
    android:theme="@style/EditTextBG"
    android:layout_marginTop="10dp"
    android:maxLines="1"
    android:hint="请输入密码"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

<TextView
    android:gravity="center"
    android:id="@+id/tv_login"
    android:background="@drawable/bt_bg"
    android:layout_marginTop="30dp"
    android:text="登录"
    android:layout_gravity="center"
    android:layout_width="200dp"
    android:layout_height="wrap_content"/>

文尾:如果可以通过jsoup爬到数据上传到bmob上就更好啦,通过每次进入主页进行判断当前数据是否和bmob上一致,变化时数据才上传bmob更新数据,这样就能实现对应数据库更新,可能会觉得为啥不每次去上传数据到bmob,或者不上传bmob直接更新,这是业务不同,在校期间就觉得缺少什么一直不清楚,工作后才发现自己业务能力太差,工作后都是不断补习请教,行业上初中级来说业务是开始,中高级就是架构,分享到此,如有疑问请留言

本文章仅供学习 未经本人允许不得转载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值