日程的增删改查

一些改动

首先,为了方便按条件查询时日期时间的比较,我们在Schedule类以及数据库表中加入了一个long类型的变量与字段,用于保存日期时间,同时也在本地数据库的工具类中做了相应的更改

由于用户的UID传递较麻烦,所以这里新建了一个类继承自Application,添加了一个名为user_id的成员变量,并添加了get set方法

添加日程功能

上次做好了本地数据库的工具类,所以添加功能是比较简单的,只需要
获取信息->判断信息合法性->封装至对象->保存至本地数据库->保存至firebase数据库

首先设计UI
这个UI也是比较简单,把所有需要的信息放上去就OK了,就只有日期时间特别点,需要用按钮来触发选择器,默认为当前时间,拖放控件,修改ID,在string.xml中加入资源文本,修改按钮的OnClick事件,做好后如图
这里写图片描述

初始化日期时间选择器部分
由于时间选择器和日期选择器差不多,所以这里只展示选择日期的部分
在窗口类中添加几个成员变量-日期选择器,侦听器,保存选择了的日期时间的int变量以及一个用于存储选择的日期时间的Calendar类对象

    private DatePickerDialog dateDlg;
    private DatePickerDialog.OnDateSetListener dateLis;
    private int mYear,mMonth,mDay;
    private int mHour,mMin;
    private Calendar mCal=Calendar.getInstance();

再定义一个当日期选择了时触发的用于更新UI的函数()

    private void OnDateChose(){
        tv_date.setText(mYear+"-"+mMonth+"-"+mDay);
    }

然后在自己定义的init函数中初始化这些对象

dateLis=new DatePickerDialog.OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
                mYear=year;
                mMonth=month;
                mDay=dayOfMonth;
                mCal.set(Calendar.YEAR,mYear);
                mCal.set(Calendar.MONTH,mMonth);
                mCal.set(Calendar.DAY_OF_MONTH,mDay);
                mMonth++;
                OnDateChose();
            }
        };
        mYear = mCal.get(Calendar.YEAR);
        mMonth = mCal.get(Calendar.MONTH);
        mDay = mCal.get(Calendar.DAY_OF_MONTH);
        mHour= mCal.get(Calendar.HOUR_OF_DAY);
        mMin= mCal.get(Calendar.MINUTE);

        dateDlg=new DatePickerDialog(this,dateLis,mYear,mMonth,mDay);
        ...
        OnDateChose();

由于保存的日期月份与选择的月份相差1,且mCal变量中以及保存了选择好的日期,所以这里为了显示时正常将mMonth变量值加一
初始化完成后调用一次更新UI用的函数以显示初始值

然后编写选择日期按钮的OnClick函数

    public void date(View v){
        dateDlg.show();
    }

接着编新建日程按钮的OnClick响应函数

public void insert(View v){
        String id= RandomUtils.getRandomId();
        String date=mYear+"-"+(mMonth+1)+"-"+mDay;
        String time=mHour+":"+mMin;
        String who=et_who.getText().toString();
        String more=et_more.getText().toString();
        int level=sp_level.getSelectedItemPosition();
        if(who.equals("") || more.equals("")){
            UIUtils.makeToast("不能留空",this);
        }
        Schedule schedule=new Schedule(id,date,time,who,more,null,level,mCal.getTimeInMillis());
        ScheduleDbUtils db=new ScheduleDbUtils(this,null);
        db.insert(schedule);
        cloud(schedule);
    }

最后编写函数cloud用于将数据备份至firebase数据库

        public void cloud(Schedule schedule){
            final AlertDialog  dlg=UIUtils.createDialog(getString(R.string.insert_cloud_handling),this);
            String uid=((GreenAppApplication)getApplication()).getUid();
            FirebaseDatabase db=FirebaseDatabase.getInstance();  db.getReference().child("schedules").child(uid).child(schedule.getId()).setValue(schedule).addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                dlg.dismiss();
                if(task.isSuccessful()){
                    UIUtils.makeToast(getString(R.string.insert_succeed),InsertScheduleActivity.this);
                }else{
                    UIUtils.makeToast(getString(R.string.insert_failed),InsertScheduleActivity.this);
                }
                InsertScheduleActivity.this.finish();
            }
        });
    }

编写查询功能

查询主要有两种方式,一种是查询全部,一种是按条件查询

改动工具类

原来的本地数据库工具类的查询功能以及不能满足需求了,需要再定义一个接受whereClause与whereArgs的查询函数并让接受id的查询函数调用那个函数

 public List<Schedule> select(String id) {
        if(id==null){
            return select(null,null);
        }else{
            String whereClause = "s_id=?";
            String[] whereArgs = {id};
            return select(whereClause,whereArgs);
        }
    }

    public List<Schedule> select(String whereClause,String[] whereArgs) {
        SQLiteDatabase db = getReadableDatabase();
        List<Schedule> result = new ArrayList<>();
        Cursor cursor = db.query(TABLE_NAME, null, whereClause, whereArgs, null, null, null);
        if (cursor.moveToFirst()) {
            for (int i = 0; i < cursor.getCount(); i++) {
                cursor.move(i);
                String id=cursor.getString(0);
                String date=cursor.getString(1);
                String time=cursor.getString(2);
                String who=cursor.getString(3);
                int level=cursor.getInt(4);
                String more=cursor.getString(5);
                long t=cursor.getLong(6);
                Schedule schedule=new Schedule(id,date,time,who,more,null,level,t);
                result.add(schedule);
            }
        }
        return result;
    }

设计UI与实现功能
这里会出现四个Activity(今后可能会用对话框代替部分)
分别是充当菜单作用的SelectSchedulesActivity,
用户输入查询条件的SelectSchedulesConditionActivity,
显示查询结果的SelectSchedulesResultActivity,
用于显示日程详细信息并提供更改与删除操作的SelectSchedulesResultMoreActivity

SelectSchedulesActivity:
由于这只是充当菜单作用,所以UI相对简单
这里写图片描述
下面两个按钮只是用于跳转至其他Activity,重点是恢复与备份功能(以后可能会移到别处或自动处理)
这里把两个功能分开来做
备份将本地数据同步到云端,就需要获取本地的所有日程,然后挨个上传至服务器(以后可能会加入一个字段来保存日程内容的MD5,如果MD5且ID相同的日程就跳过以减少服务器与客户端的负担)

public void cloud(View v){
        str_id=R.string.select_cloud_succeed;
        List<Schedule> schedules=db.select(null);
        if(schedules==null || schedules.size()==0){
            UIUtils.makeToast(getString(str_id),SelectSchedulesActivity.this);
            return;
        }
        FirebaseDatabase fdb=FirebaseDatabase.getInstance();
        final AlertDialog dlg=UIUtils.createDialog(getString(R.string.select_cloud_handling),this);
        for(final Schedule schedule:schedules){
            DatabaseReference ref=fdb.getReference().child("schedules").child(uid).child(schedule.getId());
            ref.setValue(schedule).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    str_id=R.string.select_cloud_failed;
                }
            });
        }
        dlg.dismiss();
        UIUtils.makeToast(getString(str_id),SelectSchedulesActivity.this);
    }

恢复功能就是将服务器上的弄到本地数据库里面去
但由于本地数据库并不能覆盖同ID的数据
所以先判断是否存在同ID的,不存在就添加,存在就修改

   public void download(View v){
        str_id=R.string.select_download_succeed;
        FirebaseDatabase fdb=FirebaseDatabase.getInstance();
        final AlertDialog dlg=UIUtils.createDialog(getString(R.string.select_download_handling),this);
        final DatabaseReference ref=fdb.getReference().child("schedules").child(uid);
        ref.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                if(dataSnapshot.getChildrenCount()==0){
                    str_id=R.string.select_download_succeed;
                }
                Iterable<DataSnapshot> children=dataSnapshot.getChildren();
                for(DataSnapshot child:children){
                    String id=child.child("id").getValue(String.class);
                    List<Schedule> result=db.select(id);
                    if(result!=null && result.size()!=0){
                        db.update(child.getValue(Schedule.class),id);
                        continue;
                    }
                    db.insert(child.getValue(Schedule.class));
                }
            }


            @Override
            public void onCancelled(DatabaseError databaseError) {
                str_id=R.string.select_download_failed;
                return;
            }
        });
        dlg.dismiss();
        UIUtils.makeToast(getString(str_id),SelectSchedulesActivity.this);
    }

SelectSchedulesConditionActivity:
按条件查询就要考虑输入的空白数据,因为用户要使用这种查询是因为用户并不知晓所需日程的全部内容,所以这里有两种解决方案,一种是判断所输入的是否为空,如果为空那么就让该字段为任意值都可以查询到,即忽略该字段,还有一种是使用户并不用做出任何操作就可以查询到所有,这里显然是后者更方便,由于数据库中保存了日期时间化为long类型后的数据,所以用大于小于运算符就可以做出比较,文本类信息就用LIKE关键字,在所输入的数据的前后加入通配符’%’
这里的默认日期时间就是当时,默认查找当前时间之后的
等级默认是最低的那个,然后条件是大于等于,即任何日程都符合
其他的文本信息默认为空,即任何文本都可以匹配成功
这里写图片描述
UI也以选择性的控件为主,以引导用户查找
日期时间选择器前面以及介绍过了,重点在于查找部分

    public void select(View v){
        int time_con=sp_date_time_condition.getSelectedItemPosition();
        int level_con=sp_level_condition.getSelectedItemPosition();
        int level=sp_level.getSelectedItemPosition();
        long time=mCal.getTimeInMillis();
        String who=et_who.getText().toString();
        String more=et_more.getText().toString();

        String operatorTime[]={"<","=",">"};
        String operatorLevel[]={">","=","<",">=","<="};

        who="%"+who+"%";
        more="%"+more+"%";

        String whereClause="s_time_long "+operatorTime[time_con]+" ? and s_level"+operatorLevel[level_con]+" ? and s_who like ? and s_more like ?";
        String whereArgs[]={String.valueOf(time),String.valueOf(level),who,more};

        ScheduleDbUtils db=new ScheduleDbUtils(this,null);
        List<Schedule> schedules=db.select(whereClause,whereArgs);
        Intent intent=new Intent(this,SelectSchedulesResultActivity.class);
        intent.putExtra("schedules", (Serializable) schedules);
        startActivity(intent);
    }

这样就可以查找出符合条件的日程了

SelectSchedulesResultActivity:
这里的控件也就只有个ListView,用于展示查询结果
这里需要一个适配器
新建一个类MyAdapter继承自BaseAdapter,添加构造函数获取必须的数据

class MyAdapter extends  BaseAdapter{

    private List<Schedule> schedules;
    private boolean isListNull=false;
    private Context context;

    public MyAdapter(List<Schedule> schedules,boolean isListNull,Context context){
        this.schedules=schedules;
        this.isListNull=isListNull;
        this.context=context;
    }
    ...

这里在res目录下新建一个view
这里写图片描述
这里只需改动一下getCount函数以及getView函数

   @Override
    public int getCount() {
        if(isListNull){
            return 1;
        }
        return schedules.size();
    }
    ...
        @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(isListNull){
            LinearLayout layout=new LinearLayout(context);
            TextView tv=new TextView(context);
            tv.setText("没有数据");
            layout.addView(tv);
            return layout;
        }
        View view=View.inflate(context,R.layout.view_select_result,null);

        TextView tv_date,tv_time,tv_who,tv_level,tv_more;
        tv_date= (TextView) view.findViewById(R.id.select_result_tv_date);
        tv_time= (TextView) view.findViewById(R.id.select_result_tv_time);
        tv_who= (TextView) view.findViewById(R.id.select_result_tv_who);
        tv_level= (TextView) view.findViewById(R.id.select_result_tv_level);
        tv_more= (TextView) view.findViewById(R.id.select_result_tv_more);


        Schedule schedule=schedules.get(position);
        String date=schedule.getDate();
        String time=schedule.getTime();
        String who=schedule.getWho();
        String level= schedule.levelToString(context);
        String more=schedule.getMore();

        tv_date.setText(context.getString(R.string.select_result_date)+date);
        tv_time.setText(context.getString(R.string.select_result_time)+time);
        tv_who.setText(context.getString(R.string.select_result_who)+who);
        tv_level.setText(context.getString(R.string.select_result_level)+level);
        tv_more.setText(context.getString(R.string.select_result_more)+more);

        return view;
    }

这里还需要为这个ListView做一个项目点击侦听器

class MyClickListener implements AdapterView.OnItemClickListener{

    private Context context;
    private List<Schedule> schedules;

    public MyClickListener(Context context,List<Schedule> schedules){
        this.context=context;
        this.schedules=schedules;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        if(schedules.size()==0)
            return;
        Schedule schedule=schedules.get(position);
        Intent intent=new Intent(context,SelectSchedulesResultMoreActivity.class);
        intent.putExtra("schedule",schedule);
        intent.putExtra("pos",position);
        context.startActivity(intent);
    }
}

由于More窗口处理完成后需要告知Result窗口,所以这里再定义一个个广播接收者

   private BroadcastReceiver receiver=new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int what=intent.getIntExtra("what",0);
            int pos=intent.getIntExtra("pos",0);
            switch(what){
                case 0://Delete
                    schedules.remove(pos);
                    break;
                case 1://Update
                    Schedule schedule= (Schedule) intent.getSerializableExtra("schedule");
                    schedules.set(pos,schedule);
                    break;
            }
            lv_result.setAdapter(new MyAdapter(schedules,(schedules.size()==0)?true:false,context));
        }
    };

最后在init函数中设置它们

    public void init(){
        lv_result= (ListView) findViewById(R.id.select_result_lv_result);
        schedules= (List<Schedule>) getIntent().getSerializableExtra("schedules");
        boolean isListNull=false;
        if(schedules==null || schedules.size()==0){
            isListNull=true;
        }else{
            lv_result.setOnItemClickListener(new MyClickListener(this,schedules));
        }
        adapter=new MyAdapter(schedules,isListNull,this);
    }

在onCreate函数中注册广播接受者

        IntentFilter filter = new IntentFilter();
        filter.addAction("com.greenapp.note.SCHEDULE_CHANGE");
        registerReceiver(receiver,filter);

SelectSchedulesResultMoreActivity:
这里写图片描述
这个UI和insert的差不多
功能的实现也和insert类似,获取信息,然后本地数据库的update,再设置firebase数据库中的值,就ok了,删除只需删除本地数据库里的值,然后将firebase数据库里的值设置为null就ok了

db.getReference().child("schedules").child(uid).child(schedule.getId()).setValue(null)//删除
这是一个比较复杂的问题,需要涉及到前端框架 layui 和 fullcalendar 以及后端框架 Spring Boot 和 JPA 的使用。我可以给你提供一些思路和代码片段供参考。 前端部分: 1. 在 HTML 页面中引入 layui 和 fullcalendar 的相关资源文件。 ```html <link rel="stylesheet" href="https://cdn.staticfile.org/layui/2.5.7/css/layui.css" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.2/fullcalendar.min.css" /> <script src="https://cdn.staticfile.org/layui/2.5.7/layui.all.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.2/fullcalendar.min.js"></script> ``` 2. 在 HTML 页面中添加一个用于显示日历的 div 元素。 ```html <div id="calendar"></div> ``` 3. 在 JavaScript 中初始化 fullcalendar,并获取后端返回的日程列表数据。 ```javascript layui.use(['layer'], function() { var layer = layui.layer; $('#calendar').fullCalendar({ header: { left: 'prev,next today', center: 'title', right: 'month,agendaWeek,agendaDay' }, defaultView: 'month', editable: true, events: function(start, end, timezone, callback) { $.ajax({ url: '/events', type: 'GET', dataType: 'json', success: function(response) { var events = []; response.forEach(function(event) { events.push({ id: event.id, title: event.title, start: event.startTime, end: event.endTime }); }); callback(events); }, error: function() { layer.alert('获取日程列表失败'); } }); } }); }); ``` 4. 在 JavaScript 中添加一个用于弹出添加日程的表单的函数。 ```javascript function addEvent() { layer.open({ type: 1, title: '添加日程', content: $('#add-event-form'), area: ['500px', 'auto'], btn: ['保存', '取消'], yes: function(index, layero) { // 提交表单数据并保存日程 $.ajax({ url: '/events', type: 'POST', data: $('#add-event-form').serialize(), success: function() { $('#calendar').fullCalendar('refetchEvents'); layer.close(index); }, error: function() { layer.alert('添加日程失败'); } }); } }); } ``` 后端部分: 1. 创建一个实体类 Event,用于表示日程信息。 ```java @Entity public class Event { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; @Temporal(TemporalType.TIMESTAMP) private Date startTime; @Temporal(TemporalType.TIMESTAMP) private Date endTime; // 省略 getter 和 setter 方法 } ``` 2. 创建一个 EventRepository 接口,继承 JpaRepository,用于对 Event 实体进行增删改查操作。 ```java public interface EventRepository extends JpaRepository<Event, Long> { } ``` 3. 创建一个 EventController 类,用于处理前端请求。 ```java @RestController public class EventController { @Autowired private EventRepository eventRepository; @GetMapping("/events") public List<Event> list() { return eventRepository.findAll(); } @PostMapping("/events") public void add(@Valid Event event) { eventRepository.save(event); } @PutMapping("/events/{id}") public void update(@PathVariable Long id, @Valid Event event) { event.setId(id); eventRepository.save(event); } @DeleteMapping("/events/{id}") public void delete(@PathVariable Long id) { eventRepository.deleteById(id); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值