📜  Spring MVC CRUD 与示例

📅  最后修改于: 2022-05-13 01:55:27.576000             🧑  作者: Mango

Spring MVC CRUD 与示例

Spring MVC 是一个用于构建 Web 应用程序的 Web MVC 框架。它是一个与 spring boot、spring-security 等相同的 spring 模块。术语 MVC 代表 Model-View-Controller 架构。在本文中,我们将构建一个简单的课程跟踪 CRUD 应用程序,该应用程序将专注于 Spring MVC 模块。 CRUD 代表创建、读取、更新和删除。

项目结构

项目结构

项目结构

依赖项

如果还没有,请将以下依赖项添加到build.gradle文件中。

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.projectlombok:lombok:1.18.20'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'mysql:mysql-connector-java'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

模型层

使用一些 JPA 和 Lombok 注释创建一个简单的 POJO(普通旧Java对象)。

  • @NoArgsConstructor –此注解生成不带参数的构造函数。
  • @AllArgsConstructor –此注释生成具有所有字段参数的构造函数。
  • @Data –此注解生成 getter、setter、toString、必需的参数构造函数、equals 和 hashCode。
  • @Entity——这个注解定义了一个类可以映射到一个表。
  • @Table –此注释指定用于映射的数据库表的名称。
  • @Id –此注释标记实体的主键。
  • @GeneratedValue –此注解提供了主键值的生成策略规范。
  • @Column –此注释标记表中该特定属性的列名。
Java
import lombok.*;
import javax.persistence.*;
  
@NoArgsConstructor
@AllArgsConstructor
@Data
@Entity
@Table(name = "courses")
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
  
    @Column(name = "course_name") 
    private String courseName;
    @Column(name = "instructor")
    private String instructor;
    @Column(name = "email")
    private String email;
}


Java
import com.example.testing_001.model.Course;
import org.springframework.data.jpa.repository.JpaRepository;
  
@Repository
public interface CourseRepository extends JpaRepository {
  
}


Java
import com.example.testing_001.model.Course;
import java.util.List;
import org.springframework.data.domain.Page;
  
public interface CourseService {
    List getAllCourses();
    void saveCourse(Course course);
    Course getCourseById(long id);
    void deleteCourseById(long id);
    Page findPaginated(int pageNum, int pageSize,
                               String sortField,
                               String sortDirection);
}


Java
import com.example.testing_001.model.Course;
import com.example.testing_001.repository.CourseRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
  
import java.util.List;
import java.util.Optional;
  
@Service
public class CourseServiceImpl implements CourseService{
  
    @Autowired
    private CourseRepository courseRepository;
  
    @Override
    public List getAllCourses() {
        return courseRepository.findAll();
    }
  
    @Override
    public void saveCourse(Course course) {
        this.courseRepository.save(course);
    }
  
    @Override
    public Course getCourseById(long id) {
        Optional optionalCourse = courseRepository.findById(id);
        Course course = null;
        if (optionalCourse.isPresent()) {
            course = optionalCourse.get();
        } else {
            throw new RuntimeException("Course not found for id : " + id);
        }
        return course;
    }
  
    @Override
    public void deleteCourseById(long id) {
        this.courseRepository.deleteById(id);
    }
  
    @Override
    public Page findPaginated(int pageNum, int pageSize, String sortField, String sortDirection) {
        Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortField).ascending() :
                Sort.by(sortField).descending();
  
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize, sort);
        return this.courseRepository.findAll(pageable);
    }
}


Java
import com.example.testing_001.model.Course;
import com.example.testing_001.service.CourseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
  
import java.util.List;
  
@Controller
public class CourseController {
  
    @Autowired
    private CourseService courseService;
  
    @GetMapping("/")
    public String viewHomePage(Model model) {
        return findPaginated(1, "courseName", "asc", model);
    }
  
    @GetMapping("/add")
    public String showNewCourseForm(Model model) {
        Course Course = new Course();
        model.addAttribute("course", Course);
        return "new_course";
    }
  
    @PostMapping("/save")
    public String saveCourse(@ModelAttribute("course") Course course) {
        // save Course to database
        courseService.saveCourse(course);
        return "redirect:/";
    }
  
    @GetMapping("/update/{id}")
    public String showFormForUpdate(@PathVariable( value = "id") long id, Model model) {
  
        Course course = courseService.getCourseById(id);
        model.addAttribute("course", course);
        return "update_course";
    }
  
    @GetMapping("/delete/{id}")
    public String deleteCourse(@PathVariable (value = "id") long id) {
  
        this.courseService.deleteCourseById(id);
        return "redirect:/";
    }
  
  
    @GetMapping("/page/{pageNo}")
    public String findPaginated(@PathVariable (value = "pageNo") int pageNo,
                                @RequestParam("sortField") String sortField,
                                @RequestParam("sortDir") String sortDir,
                                Model model) {
        int pageSize = 5;
  
        Page page = courseService.findPaginated(pageNo, pageSize, sortField, sortDir);
        List listCourses = page.getContent();
  
        model.addAttribute("currentPage", pageNo);
        model.addAttribute("totalPages", page.getTotalPages());
        model.addAttribute("totalItems", page.getTotalElements());
  
        model.addAttribute("sortField", sortField);
        model.addAttribute("sortDir", sortDir);
        model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");
  
        model.addAttribute("listCourses", listCourses);
        return "index";
    }
}


HTML



  
  Course Tracker
  
  
  


  
  

Courses List

      Add Course                                                                                                         
                   Course Name                           Course Instructor                           Course Email        Actions
Update         Delete       
     
    
      
        Total Rows: [[${totalItems}]]       
      
                                             [[${i}]]                         [[${i}]]                                 
      
        Next         Next       
         
        Last         Last       
    
  


HTML



    
    Course 
    


    

Course Tracker

    
    

Save Course

       
                                                 
       
        Back to Course List


HTML



    
    Course Tracker
  
    


    

Course Tracker

    
    

Update Course

       
                                                             
       
        Back to Course List


DAO(数据访问对象)/存储库层

  • @Repository:这个注解是一个标记存储库类的构造型。它表明带注释的类充当可以在其上进行 CRUD 操作的数据库。
  • JpaRepository< Course, Long > : JpaRepository 是存储库的特定于 JPA 的扩展。它包含 CrudRepository 和 PagingAndSortingRepository 的完整 API。因此它包含用于基本 CRUD 操作的 API 以及用于分页和排序的 API。在这里,我们为员工启用数据库操作。要了解有关 Spring Data Jpa 的更多信息,请参阅本文。

Java

import com.example.testing_001.model.Course;
import org.springframework.data.jpa.repository.JpaRepository;
  
@Repository
public interface CourseRepository extends JpaRepository {
  
}

服务层

服务层提供了对数据层的抽象。其主要目的是满足业务需求。将业务逻辑与应用程序逻辑分开总是更好。

Java

import com.example.testing_001.model.Course;
import java.util.List;
import org.springframework.data.domain.Page;
  
public interface CourseService {
    List getAllCourses();
    void saveCourse(Course course);
    Course getCourseById(long id);
    void deleteCourseById(long id);
    Page findPaginated(int pageNum, int pageSize,
                               String sortField,
                               String sortDirection);
}

类(如下所述)CourseServiceImpl 实现了 CourseService 接口,并为我们提供了所有 CRUD 操作逻辑,也就是我们这里的业务逻辑。

使用的注释:

  • @Service –此注解是一个原型,用于在服务层注解类。
  • @Autowired –此注解用于将一个 bean 自动装配到另一个 bean。

Java

import com.example.testing_001.model.Course;
import com.example.testing_001.repository.CourseRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
  
import java.util.List;
import java.util.Optional;
  
@Service
public class CourseServiceImpl implements CourseService{
  
    @Autowired
    private CourseRepository courseRepository;
  
    @Override
    public List getAllCourses() {
        return courseRepository.findAll();
    }
  
    @Override
    public void saveCourse(Course course) {
        this.courseRepository.save(course);
    }
  
    @Override
    public Course getCourseById(long id) {
        Optional optionalCourse = courseRepository.findById(id);
        Course course = null;
        if (optionalCourse.isPresent()) {
            course = optionalCourse.get();
        } else {
            throw new RuntimeException("Course not found for id : " + id);
        }
        return course;
    }
  
    @Override
    public void deleteCourseById(long id) {
        this.courseRepository.deleteById(id);
    }
  
    @Override
    public Page findPaginated(int pageNum, int pageSize, String sortField, String sortDirection) {
        Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortField).ascending() :
                Sort.by(sortField).descending();
  
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize, sort);
        return this.courseRepository.findAll(pageable);
    }
}

控制器层

在 Spring MVC 中,控制器层是用于处理 Web 请求的架构的顶层。然后根据请求的类型,将其传递给相应的层。

使用的注释:

  • @Controller –此注释标记特定类充当控制器的角色。
  • @GetMapping –此注释标记 HTTP GET 请求到特定处理程序方法的映射。
  • @PostMapping –此注释标记 HTTP POST 请求到特定方法处理程序的映射。

Java

import com.example.testing_001.model.Course;
import com.example.testing_001.service.CourseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
  
import java.util.List;
  
@Controller
public class CourseController {
  
    @Autowired
    private CourseService courseService;
  
    @GetMapping("/")
    public String viewHomePage(Model model) {
        return findPaginated(1, "courseName", "asc", model);
    }
  
    @GetMapping("/add")
    public String showNewCourseForm(Model model) {
        Course Course = new Course();
        model.addAttribute("course", Course);
        return "new_course";
    }
  
    @PostMapping("/save")
    public String saveCourse(@ModelAttribute("course") Course course) {
        // save Course to database
        courseService.saveCourse(course);
        return "redirect:/";
    }
  
    @GetMapping("/update/{id}")
    public String showFormForUpdate(@PathVariable( value = "id") long id, Model model) {
  
        Course course = courseService.getCourseById(id);
        model.addAttribute("course", course);
        return "update_course";
    }
  
    @GetMapping("/delete/{id}")
    public String deleteCourse(@PathVariable (value = "id") long id) {
  
        this.courseService.deleteCourseById(id);
        return "redirect:/";
    }
  
  
    @GetMapping("/page/{pageNo}")
    public String findPaginated(@PathVariable (value = "pageNo") int pageNo,
                                @RequestParam("sortField") String sortField,
                                @RequestParam("sortDir") String sortDir,
                                Model model) {
        int pageSize = 5;
  
        Page page = courseService.findPaginated(pageNo, pageSize, sortField, sortDir);
        List listCourses = page.getContent();
  
        model.addAttribute("currentPage", pageNo);
        model.addAttribute("totalPages", page.getTotalPages());
        model.addAttribute("totalItems", page.getTotalElements());
  
        model.addAttribute("sortField", sortField);
        model.addAttribute("sortDir", sortDir);
        model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");
  
        model.addAttribute("listCourses", listCourses);
        return "index";
    }
}

HTML 模板

我们使用 thymleaf 作为我们的模板引擎,而不是传统的 jsps。

主页

HTML




  
  Course Tracker
  
  
  


  
  

Courses List

      Add Course                                                                                                         
                   Course Name                           Course Instructor                           Course Email        Actions
Update         Delete       
     
    
      
        Total Rows: [[${totalItems}]]       
      
                                             [[${i}]]                         [[${i}]]                                 
      
        Next         Next       
         
        Last         Last       
    
  

添加课程页面

HTML




    
    Course 
    


    

Course Tracker

    
    

Save Course

       
                                                 
       
        Back to Course List

更新课程页面

HTML




    
    Course Tracker
  
    


    

Course Tracker

    
    

Update Course

       
                                                             
       
        Back to Course List

CRUD 操作

创建课程

添加课程

添加课程

阅读课程

查看课程列表 - 第 1 页

查看课程列表 - 第 1 页

查看课程列表 - 第 2 页

查看课程列表 - 第 2 页

更新课程

更新课程

更新课程

课程更新成功

课程更新成功

课程更新成功

删除课程

删除了更新的课程

删除了更新的课程