网站/小程序/APP个性化定制开发,二开,改版等服务,加扣:8582-36016

    说明:只是爬虫的一个实现案例,所以没有多做功能,只做了登录跟课表功能,课表有修改周次,单击课程显示课程详细信息等功能。

    开发平台:Android Studio

    界面

    使用TimetableView android课程表控件,需要添加依赖

    jsoup依赖:compile 'org.jsoup:jsoup:1.10.2'

    界面控件依赖: compile 'com.zhuangfei:TimetableView:2.0.6'


    界面效果如下:

    20190405202127200.jpg


    实现原理(爬虫实现)

    使用jsoup爬取教务系统数据,connect()方法连接教务系统,直接利用cookie连接学生课表页面,解析返回的HTML页面获取该用户的全部课程并封装为java对象,再存入数据库,可以使用java后台服务器json数据给android客户端,android客户端解析json数据,然后将课表数据展示出来。由于本案例小而单一,因此没有配置服务器,改为将爬取的数据直接存入到android本地数据库SQLite,课表的展示去本地数据库查询即可。

    (注:各个学校学院的教务系统不尽相同,具体如何爬取数据详见jsoup官方网站jsoup)


    实体类:

    public class MySubject implements ScheduleEnable {
        public static final String EXTRAS_ID="extras_id";
        public static final String EXTRAS_NUMBER="extras_number";
        //小班号
        public static final String EXTRAS_AD_URL="extras_ad_url";
        //广告Url
        private int id;
        /*
        * 班号
        * */
        private String number;
        /**
         * 课程名
         */
        private String name;
        //无用数据
        private String time;
        /**
         * 教室
         */
        private String room;
        /**
         * 教师
         */
        private String teacher;
        /**
         * 第几周至第几周上
         */
        private List<Integer> weekList;
        /**
         * 开始上课的节次
         */
        private int start;
        /**
         * 上课节数
         */
        private int step;
        /**
         * 周几上
         */
        private int day;
        private String term;
        /**
         *  一个随机数,用于对应课程的颜色
         */
        private int colorRandom = 0;
        private String url;
        public void setUrl(String url) {
            this.url = url;
        }
        public String getUrl() {
            return url;
        }
        public MySubject() {
            // TODO Auto-generated constructor stub
        }
        public void setTime(String time) {
            this.time = time;
        }
        public String getTime() {
            return time;
        }
        public void setTerm(String term) {
            this.term = term;
        }
        public String getTerm() {
            return term;
        }
        public MySubject(String term,String name, String room, String teacher, List<Integer> weekList, int start, int step, int day, int colorRandom,String time,String number) {
            super();
            this.term=term;
            this.name = name;
            this.room = room;
            this.teacher = teacher;
            this.weekList=weekList;
            this.start = start;
            this.step = step;
            this.day = day;
            this.colorRandom = colorRandom;
            this.time = time;
            this.number = number;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getRoom() {
            return room;
        }
        public void setRoom(String room) {
            this.room = room;
        }
        public String getTeacher() {
            return teacher;
        }
        public void setTeacher(String teacher) {
            this.teacher = teacher;
        }
        public void setWeekList(List<Integer> weekList) {
            this.weekList = weekList;
        }
        public List<Integer> getWeekList() {
            return weekList;
        }
        public int getStart() {
            return start;
        }
        public void setStart(int start) {
            this.start = start;
        }
        public int getStep() {
            return step;
        }
        public void setStep(int step) {
            this.step = step;
        }
        public int getDay() {
            return day;
        }
        public void setDay(int day) {
            this.day = day;
        }
        public int getColorRandom() {
            return colorRandom;
        }
        public void setColorRandom(int colorRandom) {
            this.colorRandom = colorRandom;
        }
        @Override
        public Schedule getSchedule() {
            Schedule schedule=new Schedule();
            schedule.setDay(getDay());
            schedule.setName(getName());
            schedule.setRoom(getRoom());
            schedule.setStart(getStart());
            schedule.setStep(getStep());
            schedule.setTeacher(getTeacher());
            schedule.setWeekList(getWeekList());
            schedule.setColorRandom(2);
            schedule.putExtras(EXTRAS_ID,getId());
            schedule.putExtras(EXTRAS_AD_URL,getUrl());
            schedule.putExtras(EXTRAS_NUMBER,getNumber());
            return schedule;
        }
        public void setId(int id) {
            this.id = id;
        }
        public int getId() {
            return id;
        }
        public String getNumber() {
            return number;
        }
        public void setNumber(String number) {
            this.number = number;
        }
    }


    课表界面,对依赖的课表控件进行了部分修改

    数据源改为本地数据库查询,实现了动态获取数据源:mySubjects = getLocalSubjectData();


    课表界面:

    /**
     * 课表Activity
     * 
     */
    public class BaseFuncActivity extends AppCompatActivity implements View.OnClickListener{
        private static final String TAG = "BaseFuncActivity";
        //控件
        TimetableView mTimetableView;
        WeekView mWeekView;
        Button moreButton;
        LinearLayout layout;
        TextView titleTextView;
        List<MySubject> mySubjects;
        //记录切换的周次,不一定是当前周
        int target = -1;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_base_func);
            moreButton = (Button) findViewById(R.id.id_more);
            moreButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    showPopmenu();
                }
            });
            //数据源
    //        mySubjects = SubjectRepertory.loadDefaultSubjects2();
            //获取本地数据库数据
            mySubjects = getLocalSubjectData();
            //mySubjects.addAll(SubjectRepertory.loadDefaultSubjects());
            titleTextView = (TextView) findViewById(R.id.id_title);
            layout = (LinearLayout) findViewById(R.id.id_layout);
            layout.setOnClickListener(this);
            initTimetableView();//初始化
            setMonthWidth();//设置月份宽度
    //        showTime();//显示时间
            buildItemText();//设置课程文本内容
        }
       //获取本地数据库数据
        private List<MySubject> getLocalSubjectData() {
            List<MySubject> data = DaoImpl.GetCourceData();
            if(!GetSaveStatus()){//非登录状态
                DaoImpl.ClearCource();//清空表格
            }
            return data;
        }
        //判断登录状态
        private boolean GetSaveStatus() {
            SharedPreferences Preferences=getSharedPreferences("userInfo",MODE_PRIVATE);
            String username=Preferences.getString("username","");
            String password=Preferences.getString("password","");
            if(username.equals("")&&password.equals("")){
                return false;
            }else{
                return true;
            }
        }
        /**
         * 初始化课程控件
         */
        private void initTimetableView() {
            //获取控件
            mWeekView = (WeekView) findViewById(R.id.id_weekview);
            mTimetableView = (TimetableView) findViewById(R.id.id_timetableView);
            //设置周次选择属性
            mWeekView.source(mySubjects)
                    .curWeek(getLocalWeek())
                    .callback(new IWeekView.OnWeekItemClickedListener() {
                        @Override
                        public void onWeekClicked(int week) {
                            int cur = mTimetableView.curWeek();
                            //更新切换后的日期,从当前周cur->切换的周week
                            mTimetableView.onDateBuildListener()
                                    .onUpdateDate(cur, week);
                            mTimetableView.changeWeekOnly(week);
                        }
                    })
                    .callback(new IWeekView.OnWeekLeftClickedListener() {
                        @Override
                        public void onWeekLeftClicked() {
                            onWeekLeftLayoutClicked();
                        }
                    })
                    .isShow(false)//设置隐藏,默认显示
                    .showView();
            mTimetableView.source(mySubjects)
                    .curWeek(getLocalWeek())
                    .curTerm("")
                    .maxSlideItem(16)
                    .monthWidthDp(30)
                    //透明度
                    //日期栏0.1f、侧边栏0.1f,周次选择栏0.6f
                    //透明度范围为0->1,0为全透明,1为不透明
    //                .alpha(0.1f, 0.1f, 0.6f)
                    .callback(new ISchedule.OnItemClickListener() {
                        @Override
                        public void onItemClick(View v, List<Schedule> scheduleList) {
                            display(scheduleList);
                        }
                    })
                    .callback(new ISchedule.OnItemLongClickListener() {
                        @Override
                        public void onLongClick(View v, int day, int start) {
                            Toast.makeText(BaseFuncActivity.this,
                                    "长按:周" + day  + ",第" + start + "节",
                                    Toast.LENGTH_SHORT).show();
                        }
                    })
                    .callback(new ISchedule.OnWeekChangedListener() {
                        @Override
                        public void onWeekChanged(int curWeek) {
                            titleTextView.setText("第" + curWeek + "周");
                        }
                    })
                    //旗标布局点击监听
                    .callback(new ISchedule.OnFlaglayoutClickListener() {
                        @Override
                        public void onFlaglayoutClick(int day, int start) {
                            mTimetableView.hideFlaglayout();
                            Toast.makeText(BaseFuncActivity.this,
                                    "点击了旗标:周" + (day + 1) + ",第" + start + "节",
                                    Toast.LENGTH_SHORT).show();
                        }
                    })
                    .showView();
        }
        /*
        获取周数
        * */
        private int getLocalWeek() {
            int weekResult = -1;
            SharedPreferences preferences=getSharedPreferences("userInfo",MODE_PRIVATE);
            int startWeek = preferences.getInt("weekNumber",-1);
            //,起始周从SharedPreferences获取
            //华软教务系统总共17周
            if(startWeek<=17){
                String startDay=preferences.getString("date","");
                //起始周的星期一,从SharedPreferences获取,为yyyy-MM-dd格式
    //            String endDay= CalendarUtil.getMondayOfWeek();
    //当前周的星期一,为yyyy-MM-dd格式
                String endDay= CalendarUtil.getMondayOfWeek2();
                //当前周的星期一,为yyyy-MM-dd格式
                SharedPreferences.Editor editor=getSharedPreferences("userInfo",MODE_PRIVATE).edit();
                editor.putString("current", endDay);
                editor.commit();
                int tempweek=CalendarUtil.getTwoDay(endDay,startDay);
                //间隔天数
                int week=tempweek/7;
                if(week==0){
                    weekResult=startWeek;
                }else{
                    int finalweek=startWeek+week;
                    if(finalweek>17){
                        weekResult=17;
                    }else{
                        weekResult=finalweek;
                    }
                }
                return weekResult;
            }else{
                weekResult=17;
                return weekResult;
            }
        }
        /**
         * 周次选择布局的左侧被点击时回调<br/>
         * 对话框修改当前周次
         */
        protected void onWeekLeftLayoutClicked() {
            final String items[] = new String[20];
            int itemCount = mWeekView.itemCount();
            for (int i = 0; i < itemCount; i++) {
                items[i] = "第" + (i + 1) + "周";
            }
            target = -1;
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("设置当前周");
            builder.setSingleChoiceItems(items, mTimetableView.curWeek() - 1,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            target = i;
                        }
                    });
            builder.setPositiveButton("设置为当前周", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (target != -1) {
                        mWeekView.curWeek(target + 1).updateView();
                        mTimetableView.changeWeekForce(target + 1);
                        //把修改的周次存入SharedPreferences中
                        SharedPreferences.Editor editor=getSharedPreferences("userInfo",MODE_PRIVATE).edit();
                        editor.putInt("weekNumber",target+1);
    //                    editor.putString("date", CalendarUtil.getMondayOfWeek());
                        editor.putString("date", CalendarUtil.getMondayOfWeek2());
                        editor.commit();
    //                    Log.d("info",Integer.toString(target+1));
                    }
                }
            });
            builder.setNegativeButton("取消", null);
            builder.create().show();
        }
        /**
         * 显示内容
         *
         * @param beans
         */
        protected void display(List<Schedule> beans) {
            String str = "";
            for (Schedule bean : beans) {
                str += bean.getName() + ","+bean.getWeekList().toString()+","+bean.getTeacher()+",["+bean.getExtras().get(MySubject.EXTRAS_NUMBER)+"]\n";
            }
            Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
        }
        /**
         * 显示弹出菜单
         */
        private void showPopmenu() {
            PopupMenu popup = new PopupMenu(this, moreButton);
            popup.getMenuInflater().inflate(R.menu.popmenu_base_func, popup.getMenu());
            popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                public boolean onMenuItemClick(MenuItem item) {
                    switch (item.getItemId()) {
                        /*case R.id.top1:
                            addSubject();
                            break;
                        case R.id.top2:
                            deleteSubject();
                            break;*/
                        case R.id.top4:
                            hideNonThisWeek();
                            break;
                        case R.id.top5:
                            showNonThisWeek();
                            break;
                        /*case R.id.top6:
                            setMaxItem(8);
                            break;
                        case R.id.top7:
                            setMaxItem(10);
                            break;
                        case R.id.top8:
                            setMaxItem(12);
                            break;*/
                        case R.id.top9:
                            showTime();
                            break;
                        case R.id.top10:
                            hideTime();
                            break;
                        case R.id.top11:
                            showWeekView();
                            break;
                        case R.id.top12:
                            hideWeekView();
                            break;
                        /*case R.id.top13:
                            setMonthWidth();
                            break;
                        case R.id.top16:
                            resetMonthWidth();
                            break;*/
                        case R.id.top14:
                            hideWeekends();
                            break;
                        case R.id.top15:
                            showWeekends();
                            break;
                        case R.id.top17:
                            exitCurrentAccount();
                            break;
                        default:
                            break;
                    }
                    return true;
                }
            });
            popup.show();
        }
        /**
         * 退出当前账号
         * 清空本地账号及SharedPreferences
         */
        private void exitCurrentAccount() {
            //清空数据库
            DaoImpl.ClearCource();
            //清空SharedPreferences
            SharedPreferences.Editor editor=getSharedPreferences("userInfo",MODE_PRIVATE).edit();
            editor.putInt("weekNumber",-1);
            editor.putString("date", "");
            editor.putString("username","");
            editor.putString("password","");
            editor.putString("current", "");
            editor.commit();
            Intent intent=new Intent(BaseFuncActivity.this,MainActivity.class);
            startActivity(intent);
            finish();
        }
        /**
         * 删除课程
         * 内部使用集合维护课程数据,操作集合的方法来操作它即可
         * 最后更新一下视图(全局更新)
         */
        protected void deleteSubject() {
            int size = mTimetableView.dataSource().size();
            int pos = (int) (Math.random() * size);
            if (size > 0) {
                mTimetableView.dataSource().remove(pos);
                mTimetableView.updateView();
            }
        }
        /**
         * 添加课程
         * 内部使用集合维护课程数据,操作集合的方法来操作它即可
         * 最后更新一下视图(全局更新)
         */
        protected void addSubject() {
            List<Schedule> dataSource = mTimetableView.dataSource();
            int size = dataSource.size();
            if (size > 0) {
                Schedule schedule = dataSource.get(0);
                dataSource.add(schedule);
                mTimetableView.updateView();
            }
        }
        /**
         * 隐藏非本周课程
         * 修改了内容的显示,所以必须更新全部(性能不高)
         * 建议:在初始化时设置该属性
         * <p>
         * updateView()被调用后,会重新构建课程,课程会回到当前周
         */
        protected void hideNonThisWeek() {
            mTimetableView.isShowNotCurWeek(false).updateView();
        }
        /**
         * 显示非本周课程
         * 修改了内容的显示,所以必须更新全部(性能不高)
         * 建议:在初始化时设置该属性
         */
        protected void showNonThisWeek() {
            mTimetableView.isShowNotCurWeek(true).updateView();
        }
        /**
         * 设置侧边栏最大节次,只影响侧边栏的绘制,对课程内容无影响
         *
         * @param num
         */
        protected void setMaxItem(int num) {
            mTimetableView.maxSlideItem(num).updateSlideView();
        }
        /**
         * 显示时间
         * 设置侧边栏构建监听,TimeSlideAdapter是控件实现的可显示时间的侧边栏
         */
        protected void showTime() {
            String[] times = new String[]{
                    "09:00", "10:20", "10:40", "12:00",
                    "12:30", "13:50", "14:00", "15:20",
                    "15:30", "16:50", "17:00", "18:20",
                    "19:00", "20:20", "20:30", "21:50"
            };
            OnSlideBuildAdapter listener = (OnSlideBuildAdapter) mTimetableView.onSlideBuildListener();
            listener.setTimes(times)
                    .setTimeTextColor(Color.BLACK);
            mTimetableView.updateSlideView();
        }
        /**
         * 隐藏时间
         * 将侧边栏监听置Null后,会默认使用默认的构建方法,即不显示时间
         * 只修改了侧边栏的属性,所以只更新侧边栏即可(性能高),没有必要更新全部(性能低)
         */
        protected void hideTime() {
            mTimetableView.callback((ISchedule.OnSlideBuildListener) null);
            mTimetableView.updateSlideView();
        }
        /**
         * 显示WeekView
         */
        protected void showWeekView() {
            mWeekView.isShow(true);
        }
        /**
         * 隐藏WeekView
         */
        protected void hideWeekView() {
            mWeekView.isShow(false);
        }
        /**
         * 设置月份宽度
         */
        private void setMonthWidth() {
            mTimetableView.monthWidthDp(50).updateView();
        }
        /**
         * 设置月份宽度,默认40dp
         */
        private void resetMonthWidth() {
            mTimetableView.monthWidthDp(40).updateView();
        }
        /**
         * 修改显示的文本
         */
        public void buildItemText() {
            mTimetableView.callback(new OnItemBuildAdapter() {
                @Override
                public String getItemText(Schedule schedule, boolean isThisWeek) {
                    if (isThisWeek) return schedule.getName()+"["+schedule.getExtras().get(MySubject.EXTRAS_NUMBER)+"]"+"\n@"+schedule.getRoom();
                    return "[非本周]" + schedule.getName()+"["+schedule.getExtras().get(MySubject.EXTRAS_NUMBER)+"]"+"\n@"+schedule.getRoom();
                }
            })
                    .updateView();
        }
        /**
         * 隐藏周末
         */
        private void hideWeekends() {
            mTimetableView.isShowWeekends(false).updateView();
        }
        /**
         * 显示周末
         */
        private void showWeekends() {
            mTimetableView.isShowWeekends(true).updateView();
        }
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.id_layout:
                    //如果周次选择已经显示了,那么将它隐藏,更新课程、日期
                    //否则,显示
                    if (mWeekView.isShowing()) {
                        mWeekView.isShow(false);
                        titleTextView.setTextColor(getResources().getColor(R.color.app_course_textcolor_blue));
                        int cur = mTimetableView.curWeek();
                        mTimetableView.onDateBuildListener()
                                .onUpdateDate(cur, cur);
                        mTimetableView.changeWeekOnly(cur);
                    } else {
                        mWeekView.isShow(true);
                        titleTextView.setTextColor(getResources().getColor(R.color.app_red));
                    }
                    break;
            }
        }
    }


    登录:

    20190405200720905.jpg

    如果勾选记住登录,则将学号以及密码存入SharedPreferences中,下次打开跳过登录直接显示课表,实现了离线操作,避免了需要再次联网登录爬取数据。


    评论 0

    暂无评论
    0
    0
    0
    立即
    投稿
    发表
    评论
    返回
    顶部