📜  Angular + Spring Boot CRUD示例

📅  最后修改于: 2020-12-16 10:03:28             🧑  作者: Mango

Spring Angular CRUD应用

在本节中,我们将开发一个CRUD(创建读取更新更新删除)Web应用程序。该应用程序包含学生表单,该表单包含CRUD功能,例如添加,查看,删除和更新学生。在这种集成中,我们使用Spring Boot处理后端部分,使用Angular处理前端部分。

申请工作

  • 在将应用程序部署到服务器上后,将在Web浏览器中生成学生表格。
  • 该表格便于添加和查看学生。
  • 单击添加学生链接后,页面将重定向到创建学生表单,我们可以在其中填写所需的详细信息并提交,从而添加学生。
  • 使用查看学生链接,我们可以获取现有学生的详细信息。在这里,每个学生还包含更新和删除链接。
  • 因此,我们可以更新学生的详细信息,也可以将其从数据库中删除。
  • 完成后,在Web浏览器中提供URL http:// localhost:4200 /。

使用工具

  • 使用任何IDE来开发Spring和Hibernate项目。可能是STS / Eclipse / Netbeans。在这里,我们正在使用STS(Spring工具套件)。
  • MySQL用于数据库。
  • 使用任何IDE来开发Angular项目。它可能是Visual Studio代码/ Sublime。在这里,我们正在使用Visual Studio Code。
  • 服务器:Apache Tomcat / JBoss / Glassfish / Weblogic / Websphere。

我们使用的技术

在这里,我们使用以下技术:

  • SpringBoot 2
  • 休眠5
  • 角度6
  • MySQL数据库

创建数据库

让我们创建一个数据库indigo 。由于Hibernate自动创建了表,因此无需创建表。

弹簧模块

让我们看看我们需要遵循的Spring Boot的目录结构:

要开发CRUD应用程序,请按照以下步骤操作:-

  • 将依赖项添加到pom.xml文件。


    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.4.RELEASE
         
    
    com.main
    Student
    0.0.1-SNAPSHOT
    Student
    Demo project for Spring Boot

    
        1.8
    

    
    
        
            org.springframework.boot
            spring-boot-devtools
            true
        
    
        
            org.springframework.boot
            spring-boot-starter-data-jpa
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            mysql
            mysql-connector-java
            runtime
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


  • 创建配置类我们执行基于注释的配置,而不是XML。因此,我们创建一个类Config.java并在其中指定所需的配置。但是,还有一个配置类StudentApplication.java。此类由Spring Boot自动提供。

配置文件

package config;

import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.view.InternalResourceViewResolver;


@Configuration
@EnableTransactionManagement
@EnableAutoConfiguration(exclude = { HibernateJpaAutoConfiguration.class})
@ComponentScans(value = { @ComponentScan("boot.entry"),
          @ComponentScan("Model"),
          @ComponentScan("Controller"),
          @ComponentScan("DAO"),
          @ComponentScan("Miscallaneous"),
          @ComponentScan("Service")})
public class Config {

     @Value("${db.driver}")
        private String DB_DRIVER;

        @Value("${db.password}")
        private String DB_PASSWORD;

        @Value("${db.url}")
        private String DB_URL;

        @Value("${db.username}")
        private String DB_USERNAME;

        @Value("${hibernate.dialect}")
        private String HIBERNATE_DIALECT;

        @Value("${hibernate.show_sql}")
        private String HIBERNATE_SHOW_SQL;

        @Value("${hibernate.hbm2ddl.auto}")
        private String HIBERNATE_HBM2DDL_AUTO;

        @Value("${entitymanager.packagesToScan}")
        private String ENTITYMANAGER_PACKAGES_TO_SCAN;

        @Bean
        public LocalSessionFactoryBean sessionFactory() {
            LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
            sessionFactory.setDataSource(dataSource());
            sessionFactory.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
            Properties hibernateProperties = new Properties();
            hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
            hibernateProperties.put("hibernate.show_sql", HIBERNATE_SHOW_SQL);
            hibernateProperties.put("hibernate.hbm2ddl.auto", HIBERNATE_HBM2DDL_AUTO);
            sessionFactory.setHibernateProperties(hibernateProperties);
            return sessionFactory;
        }

        @Bean
        public DataSource dataSource() {
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName(DB_DRIVER);
            dataSource.setUrl(DB_URL);
            dataSource.setUsername(DB_USERNAME);
            dataSource.setPassword(DB_PASSWORD);
            return dataSource;
        }

        @Bean
        public HibernateTransactionManager transactionManager() {
            HibernateTransactionManager txManager = new HibernateTransactionManager();
            txManager.setSessionFactory(sessionFactory().getObject());
            return txManager;
        }
        
        @Bean
        public InternalResourceViewResolver jspViewResolver() {
            InternalResourceViewResolver resolver= new InternalResourceViewResolver();
            resolver.setPrefix("/views/");
            resolver.setSuffix(".jsp");
            return resolver;
        } 
       
       
       
    }

StudentApplication.java

package config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class StudentApplication {

    public static void main(String[] args) {
        SpringApplication.run(StudentApplication.class, args);
    }

}
  • 创建实体类在这里,我们将创建一个Entity / POJO(普通旧Java对象)类。

学生.java

package Model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="student")
public class Student {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int student_id;
    private String student_name;
    private String student_email;
    private String student_branch;
    public int getStudent_id() {
        return student_id;
    }
    public void setStudent_id(int student_id) {
        this.student_id = student_id;
    }
    public String getStudent_name() {
        return student_name;
    }
    public void setStudent_name(String student_name) {
        this.student_name = student_name;
    }
    public String getStudent_email() {
        return student_email;
    }
    public void setStudent_email(String student_email) {
        this.student_email = student_email;
    }
    public String getStudent_branch() {
        return student_branch;
    }
    public void setStudent_branch(String student_branch) {
        this.student_branch = student_branch;
    }

    
}
  • 创建DAO接口在这里,我们将创建DAO接口以执行与数据库相关的操作。

Student_DAO.java

package DAO;

import java.util.List;

import Model.Student;

public interface Student_DAO {

    public boolean saveStudent(Student student);
    public List getStudents();
    public boolean deleteStudent(Student student);
    public List getStudentByID(Student student);
    public boolean updateStudent(Student student);
}
  • 创建DAO接口实现类

Student_DAO_Imp.java

package DAO;

import java.util.List;


import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;


import Model.Student;

@Repository
public class Student_DAO_Imp  implements Student_DAO{

    @Autowired
    private SessionFactory sessionFactory;
    
    @Override
    public boolean saveStudent(Student student) {
        boolean status=false;
        try {
            sessionFactory.getCurrentSession().save(student);
            status=true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return status;
    }

    @Override
    public List getStudents() {
        Session currentSession = sessionFactory.getCurrentSession();
        Query query=currentSession.createQuery("from Student", Student.class);
        List list=query.getResultList();
        return list;
    }

    @Override
    public boolean deleteStudent(Student student) {
        boolean status=false;
        try {
            sessionFactory.getCurrentSession().delete(student);
            status=true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return status;
    }

    @Override
    public List getStudentByID(Student student) {
        Session currentSession = sessionFactory.getCurrentSession();
        Query query=currentSession.createQuery("from Student where student_id=:student_id", Student.class);
        query.setParameter("student_id", student.getStudent_id());
        List list=query.getResultList();
        return list;
    }

    @Override
    public boolean updateStudent(Student student) {
        boolean status=false;
        try {
            sessionFactory.getCurrentSession().update(student);
            status=true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return status;
    }
    
    

}
  • 创建服务层接口

在这里,我们正在创建一个服务层接口,该接口充当DAO和Entity类之间的桥梁。

Student_Service.java

package Service;

import java.util.List;
import Model.Student;

public interface Student_Service {

    
    public boolean saveStudent(Student student);
    public List getStudents();
    public boolean deleteStudent(Student student);
    public List getStudentByID(Student student);
    public boolean updateStudent(Student student);
}
  • 创建服务层实现类

Student_Service_Imp.java

package Service;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import DAO.Student_DAO;
import Model.Student;

@Service
@Transactional
public class Student_Service_Imp implements Student_Service {
 
    @Autowired
    private Student_DAO studentdao;
    
    @Override
    public boolean saveStudent(Student student) {
        return studentdao.saveStudent(student);
    }

    @Override
    public List getStudents() {
        return studentdao.getStudents();
    }

    @Override
    public boolean deleteStudent(Student student) {
        return studentdao.deleteStudent(student);
    }

    @Override
    public List getStudentByID(Student student) {
        return studentdao.getStudentByID(student);
    }

    @Override
    public boolean updateStudent(Student student) {
        return studentdao.updateStudent(student);
    }

}
  • 创建控制器类

Controller.java

package Controller;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import Model.Student;
import Service.Student_Service;

@RestController
@CrossOrigin(origins="http://localhost:4200")
@RequestMapping(value="/api")
public class Controller {
    
    @Autowired
    private Student_Service studentservice;
    
    @PostMapping("save-student")
    public boolean saveStudent(@RequestBody Student student) {
         return studentservice.saveStudent(student);
        
    }
    
    @GetMapping("students-list")
    public List allstudents() {
         return studentservice.getStudents();
        
    }
    
    @DeleteMapping("delete-student/{student_id}")
    public boolean deleteStudent(@PathVariable("student_id") int student_id,Student student) {
        student.setStudent_id(student_id);
        return studentservice.deleteStudent(student);
    }

    @GetMapping("student/{student_id}")
    public List allstudentByID(@PathVariable("student_id") int student_id,Student student) {
         student.setStudent_id(student_id);
         return studentservice.getStudentByID(student);
        
    }
    
    @PostMapping("update-student/{student_id}")
    public boolean updateStudent(@RequestBody Student student,@PathVariable("student_id") int student_id) {
        student.setStudent_id(student_id);
        return studentservice.updateStudent(student);
    }
}
  • 编辑application.properties文件在这里,我们正在编辑src / main / resources文件夹中存在的application.properties文件。以下文件包含配置属性。

application.properties

# Database
db.driver= com.mysql.jdbc.Driver
db.url= jdbc:mysql://localhost:3306/indigo
db.username=root
db.password=

# Hibernate
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
entitymanager.packagesToScan=Model

角度模块

让我们看看我们需要遵循的Angular目录结构:

  • 创建一个Angular项目

让我们使用以下命令创建一个Angular项目:

ng新角度


在这里, Angular是项目的名称。

安装Bootstrap CSS框架

使用以下命令在项目中安装引导程序。

npm install bootstrap@3.3.7-保存

现在,在style.css文件中包含以下代码。

@import "~bootstrap/dist/css/bootstrap.css";

安装Angular-DataTable

使用以下命令在项目中安装角度数据表。

npm install angular-datatable-保存

必须在app.module.ts文件的imports数组中包括DataTableModule。

  • 生成组件在Visual Studio中打开项目,然后使用以下命令生成Angular组件: ng gc AddStudent ng gc StudentList

我们还使用以下命令创建服务类:-

ng gs学生

  • 编辑app.module.ts文件
    • 导入路由-在这里,我们将导入路由文件(app-routing.module.ts)并将其包含在imports数组中。
    • Import ReactiveFormsModule-在这里,我们将为反应形式导入ReactiveFormsModule ,并在imports数组中指定它。
    • Import HttpModule-在这里,我们将为服务器请求导入HttpModule ,并在imports数组中指定它。
    • 注册服务类-在这里,我们在提供者的数组中提到了服务类。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import {DataTablesModule} from 'angular-datatables';
import { StudentListComponent } from './student-list/student-list.component';
import { AddStudentComponent } from './add-student/add-student.component';

@NgModule({
  declarations: [
    AppComponent,
    StudentListComponent,
    AddStudentComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    ReactiveFormsModule,
    HttpClientModule,
    DataTablesModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
  • 编辑app-routing.module.ts文件
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { StudentListComponent } from './student-list/student-list.component';
import { AddStudentComponent } from './add-student/add-student.component';

const routes: Routes = [
  { path: '', redirectTo: 'view-student', pathMatch: 'full' },
  { path: 'view-student', component: StudentListComponent },
  { path: 'add-student', component: AddStudentComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
  • 编辑app.component.html文件
  • 创建Student.ts

让我们使用以下命令创建一个类:-

ng班学生

现在,在Student类中指定必填字段。

export class Student {

    student_id:number;
    student_name:String;
    student_email:String;
    student_branch:String;
}

该类的目的是将指定的字段与Spring实体类的字段进行映射。

  • 编辑student.service.ts文件
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})

export class StudentService {

  private baseUrl = 'http://localhost:8080/api/';

  constructor(private http:HttpClient) { }

  getStudentList(): Observable {
    return this.http.get(`${this.baseUrl}`+'students-list');
  }

  createStudent(student: object): Observable {
    return this.http.post(`${this.baseUrl}`+'save-student', student);
  }

  deleteStudent(id: number): Observable {
    return this.http.delete(`${this.baseUrl}/delete-student/${id}`, { responseType: 'text' });
  }

  getStudent(id: number): Observable {
    return this.http.get(`${this.baseUrl}/student/${id}`);
  }

  updateStudent(id: number, value: any): Observable {
    return this.http.post(`${this.baseUrl}/update-student/${id}`, value);
  }
  
}


  • 编辑add-student.component.ts文件
import { Component, OnInit } from '@angular/core';
import { StudentService } from '../student.service';
import {FormControl,FormGroup,Validators} from '@angular/forms';
import { Student } from '../student';
@Component({
  selector: 'app-add-student',
  templateUrl: './add-student.component.html',
  styleUrls: ['./add-student.component.css']
})
export class AddStudentComponent implements OnInit {

  constructor(private studentservice:StudentService) { }

  student : Student=new Student();
  submitted = false;

  ngOnInit() {
    this.submitted=false;
  }

  studentsaveform=new FormGroup({
    student_name:new FormControl('' , [Validators.required , Validators.minLength(5) ] ),
    student_email:new FormControl('',[Validators.required,Validators.email]),
    student_branch:new FormControl()
  });

  saveStudent(saveStudent){
    this.student=new Student();   
    this.student.student_name=this.StudentName.value;
    this.student.student_email=this.StudentEmail.value;
    this.student.student_branch=this.StudentBranch.value;
    this.submitted = true;
    this.save();
  }

  

  save() {
    this.studentservice.createStudent(this.student)
      .subscribe(data => console.log(data), error => console.log(error));
    this.student = new Student();
  }

  get StudentName(){
    return this.studentsaveform.get('student_name');
  }

  get StudentEmail(){
    return this.studentsaveform.get('student_email');
  }

  get StudentBranch(){
    return this.studentsaveform.get('student_branch');
  }

  addStudentForm(){
    this.submitted=false;
    this.studentsaveform.reset();
  }
}
  • 编辑add-student.component.html文件

Create Student

Student Name is Required MinLength Error
Student Email is Required Invalid Email Format

Student Added SuccessFully!

点击添加学生,将生成以下页面:

现在,填写所需的详细信息并提交以添加学生。

  • 编辑student-list.component.ts文件
import { Component, OnInit } from '@angular/core';
import { StudentService } from '../student.service';
import { Student } from '../student';
import { Observable,Subject } from "rxjs";

import {FormControl,FormGroup,Validators} from '@angular/forms';

@Component({
  selector: 'app-student-list',
  templateUrl: './student-list.component.html',
  styleUrls: ['./student-list.component.css']
})
export class StudentListComponent implements OnInit {

 constructor(private studentservice:StudentService) { }

  studentsArray: any[] = [];
  dtOptions: DataTables.Settings = {};
  dtTrigger: Subject= new Subject();

  students: Observable;
  student : Student=new Student();
  deleteMessage=false;
  studentlist:any;
  isupdated = false;    
 

  ngOnInit() {
    this.isupdated=false;
    this.dtOptions = {
      pageLength: 6,
      stateSave:true,
      lengthMenu:[[6, 16, 20, -1], [6, 16, 20, "All"]],
      processing: true
    };   
    this.studentservice.getStudentList().subscribe(data =>{
    this.students =data;
    this.dtTrigger.next();
    })
  }
  
  deleteStudent(id: number) {
    this.studentservice.deleteStudent(id)
      .subscribe(
        data => {
          console.log(data);
          this.deleteMessage=true;
          this.studentservice.getStudentList().subscribe(data =>{
            this.students =data
            })
        },
        error => console.log(error));
  }

  updateStudent(id: number){
    this.studentservice.getStudent(id)
      .subscribe(
        data => {
          this.studentlist=data           
        },
        error => console.log(error));
  }

  studentupdateform=new FormGroup({
    student_id:new FormControl(),
    student_name:new FormControl(),
    student_email:new FormControl(),
    student_branch:new FormControl()
  });

  updateStu(updstu){
    this.student=new Student(); 
   this.student.student_id=this.StudentId.value;
   this.student.student_name=this.StudentName.value;
   this.student.student_email=this.StudentEmail.value;
   this.student.student_branch=this.StudentBranch.value;
   console.log(this.StudentBranch.value);
   

   this.studentservice.updateStudent(this.student.student_id,this.student).subscribe(
    data => {     
      this.isupdated=true;
      this.studentservice.getStudentList().subscribe(data =>{
        this.students =data
        })
    },
    error => console.log(error));
  }

  get StudentName(){
    return this.studentupdateform.get('student_name');
  }

  get StudentEmail(){
    return this.studentupdateform.get('student_email');
  }

  get StudentBranch(){
    return this.studentupdateform.get('student_branch');
  }

  get StudentId(){
    return this.studentupdateform.get('student_id');
  }

  changeisUpdate(){
    this.isupdated=false;
  }
}
  • 编辑student-list.component.html文件

Students


Student Data Deleted

Student Name Student Email Student Branch Action
{{student.student_name}} {{student.student_email}} {{student.student_branch}}  

点击查看学生,将生成以下页面:

在单击Update Student时,将出现以下引导程序模式:

在这里,我们可以更新现有学生的详细信息。

单击删除后,现有学生将从数据库中删除。让我们看看删除特定学生后的结果。