3.10

手机端新课程添加功能实现
设计思想:
本功能旨在实现一个手机端的课程添加界面,主要包含以下验证逻辑:

  1. 课程名称唯一性验证
  2. 教师姓名合法性验证(限定9位特定教师)
  3. 上课地点格式验证(必须以特定教学楼前缀开头)
  4. 数据持久化到远程数据库

采用MVVM架构设计,前端使用Android原生开发,后端使用Spring Boot提供RESTful API,数据库使用MySQL。

源程序代码:

  1. Android前端代码
    activity_add_course.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/etCourseName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="课程名称"/>
        
    <EditText
        android:id="@+id/etTeacher"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="任课教师"/>
        
    <EditText
        android:id="@+id/etLocation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="上课地点"/>
        
    <Button
        android:id="@+id/btnSave"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="保存"/>
</LinearLayout>

AddCourseActivity.kt

class AddCourseActivity : AppCompatActivity() {
    private lateinit var binding: ActivityAddCourseBinding
    private val viewModel: CourseViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityAddCourseBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.btnSave.setOnClickListener {
            val courseName = binding.etCourseName.text.toString()
            val teacher = binding.etTeacher.text.toString()
            val location = binding.etLocation.text.toString()

            if (validateInput(courseName, teacher, location)) {
                viewModel.addCourse(courseName, teacher, location)
            }
        }

        viewModel.result.observe(this) { result ->
            when (result) {
                is Result.Success -> {
                    Toast.makeText(this, "课程添加成功", Toast.LENGTH_SHORT).show()
                    finish()
                }
                is Result.Error -> {
                    Toast.makeText(this, result.message, Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    private fun validateInput(courseName: String, teacher: String, location: String): Boolean {
        if (courseName.isEmpty()) {
            Toast.makeText(this, "课程名称不能为空", Toast.LENGTH_SHORT).show()
            return false
        }

        val validTeachers = listOf("王建民", "刘立嘉", "刘丹", "杨子光", "张云霞", "武永亮", "高飞", "孙静", "黄荣峰")
        if (!validTeachers.contains(teacher)) {
            Toast.makeText(this, "教师不在允许名单中", Toast.LENGTH_SHORT).show()
            return false
        }

        val validPrefixes = listOf("一教", "二教", "三教", "基教")
        if (!validPrefixes.any { location.startsWith(it) }) {
            Toast.makeText(this, "上课地点必须以一教、二教、三教或基教开头", Toast.LENGTH_SHORT).show()
            return false
        }

        return true
    }
}
  1. 后端Spring Boot代码
    CourseController.java
@RestController
@RequestMapping("/api/courses")
public class CourseController {
    
    @Autowired
    private CourseService courseService;

    @PostMapping
    public ResponseEntity<?> addCourse(@RequestBody CourseDto courseDto) {
        try {
            Course course = courseService.addCourse(courseDto);
            return ResponseEntity.ok(course);
        } catch (DuplicateCourseException e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
}

CourseService.java

@Service
public class CourseService {
    
    @Autowired
    private CourseRepository courseRepository;

    public Course addCourse(CourseDto courseDto) throws DuplicateCourseException {
        if (courseRepository.existsByCourseName(courseDto.getCourseName())) {
            throw new DuplicateCourseException("课程名称重复,重新录入");
        }
        
        Course course = new Course();
        course.setCourseName(courseDto.getCourseName());
        course.setTeacher(courseDto.getTeacher());
        course.setLocation(courseDto.getLocation());
        
        return courseRepository.save(course);
    }
}
3. 数据库表结构
CREATE TABLE courses (
    id INT AUTO_INCREMENT PRIMARY KEY,
    course_name VARCHAR(100) NOT NULL UNIQUE,
    teacher VARCHAR(50) NOT NULL,
    location VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
  1. 输入验证失败 :当教师姓名不在允许名单中时提示错误
  2. 地点验证失败 :当地点不以指定前缀开头时提示错误
  3. 课程重复 :当课程名称已存在时提示错误
  4. 添加成功 :所有验证通过后成功添加课程
    编程总结分析
实现难点
  1. 输入验证逻辑 :需要在客户端和服务端都实现验证逻辑,确保数据一致性
  2. 网络请求处理 :Android端需要正确处理网络请求和响应,包括错误情况
  3. 用户体验 :在验证失败时给出明确的错误提示

解决方案:

  1. 采用前后端双重验证机制,确保数据有效性
  2. 使用Kotlin协程处理网络请求,避免主线程阻塞
  3. 设计清晰的错误提示信息,帮助用户理解问题

改进方向:

  1. 增加自动补全功能,帮助用户输入教师姓名和地点

  2. 实现离线缓存功能,在网络不可用时暂存数据

  3. 添加更多课程相关信息,如上课时间、学分等

    PSP0级时间记录日志

任务 开始时间 结束时间 耗时 备注
需求分析 10:00 10:30 30min 明确功能需求
UI设计 10:30 11:00 30min 设计界面布局
Android编码 11:00 12:30 90min 实现前端逻辑
后端API开发 14:00 15:30 90min 实现RESTful API
数据库设计 15:30 16:00 30min 设计表结构
联调测试 16:00 17:30 90min 前后端联调
文档撰写 17:30 18:00 30min 编写博客和记录
总计 5h

通过本次开发,我掌握了手机端表单验证的实现方法,以及如何设计前后端分离的应用架构。在未来的开发中,我会更加注重用户体验和代码的可维护性。

posted @ 2025-03-10 21:51  李蕊lr  阅读(9)  评论(0)    收藏  举报