Lab 4 - доп.задание
This commit is contained in:
parent
f9c5202f6b
commit
ec634ba472
@ -6,6 +6,8 @@ import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import DrivingSchools from './components/DrivingSchools.jsx';
|
||||
import Categories from './components/Categories.jsx';
|
||||
import OneDrivingSchool from './components/OneDrivingSchool.jsx';
|
||||
import CountStudInCategory from './components/CountStudInCategory.jsx';
|
||||
|
||||
function Router(props) {
|
||||
return useRoutes(props.rootRoute);
|
||||
}
|
||||
@ -17,6 +19,7 @@ function Router(props) {
|
||||
{ path: '/drivingSchools', element: <DrivingSchools />, label: 'Автошколы' },
|
||||
{ path: '/students', element: <Students />, label: 'Студенты' },
|
||||
{ path: '/categories', element: <Categories />, label: 'Категории' },
|
||||
{ path: '/studcategory', element: <CountStudInCategory />, label: 'Количество студентов в категории' },
|
||||
{ path: '/drivingSchool/:id', element: <OneDrivingSchool />},
|
||||
];
|
||||
const links = routes.filter(route => route.hasOwnProperty('label'));
|
||||
|
12
front/src/components/CatalogForGroup.jsx
Normal file
12
front/src/components/CatalogForGroup.jsx
Normal file
@ -0,0 +1,12 @@
|
||||
import TableForGroup from "./commons/TableForGroup.jsx";
|
||||
// это абстрактный компонент для всех справочников
|
||||
export default function CatalogForGroup(props) {
|
||||
|
||||
return <>
|
||||
<div>{props.name}</div>
|
||||
<TableForGroup
|
||||
headers={props.headers}
|
||||
items={props.items}
|
||||
/></>
|
||||
|
||||
}
|
49
front/src/components/CatalogSC.jsx
Normal file
49
front/src/components/CatalogSC.jsx
Normal file
@ -0,0 +1,49 @@
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import TableSC from "./commons/TableSC.jsx";
|
||||
import { useState} from 'react';
|
||||
import ModalForm from './commons/ModalForm.jsx';
|
||||
// это абстрактный компонент для всех справочников
|
||||
export default function CatalogSC(props) {
|
||||
const [show, setShow] = useState(false);
|
||||
const [modalTitle, setModalTitle] = useState("");
|
||||
|
||||
const handleClose = () => setShow(false);
|
||||
const handleShow = () => setShow(true);
|
||||
|
||||
|
||||
function handleAdd() {
|
||||
setModalTitle("Добавление");
|
||||
props.onBtnAdd();
|
||||
handleShow();
|
||||
}
|
||||
function handleEdit(itemId) {
|
||||
setModalTitle("Редактирование");
|
||||
props.onEdit(itemId);
|
||||
handleShow();
|
||||
}
|
||||
function handleRemove(item) {
|
||||
props.onDelete(item);
|
||||
}
|
||||
function changeData(event) {
|
||||
props.onFormChanged(event);
|
||||
}
|
||||
|
||||
return <>
|
||||
<div>{props.name}</div>
|
||||
<Button variant="success" onClick={handleAdd}>Добавить</Button>
|
||||
<TableSC
|
||||
headers={props.headers}
|
||||
items={props.items}
|
||||
onEdit={handleEdit}
|
||||
onDelete={handleRemove}
|
||||
/>
|
||||
<ModalForm
|
||||
show={show}
|
||||
onClose={handleClose}
|
||||
modalTitle={modalTitle}
|
||||
// onSubmit={submitForm}
|
||||
onChange={changeData}
|
||||
form={props.form}
|
||||
/></>
|
||||
|
||||
}
|
@ -3,7 +3,7 @@ import Form from 'react-bootstrap/Form';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import { useState, useEffect } from 'react';
|
||||
import DataService from '../services/DataService';
|
||||
import Catalog from "./Catalog.jsx";
|
||||
import CatalogSC from "./CatalogSC.jsx";
|
||||
|
||||
|
||||
export default function Categories(props) {
|
||||
@ -94,7 +94,7 @@ export default function Categories(props) {
|
||||
</Form>
|
||||
|
||||
return <div className="container-lg pt-5 min-vh-100">
|
||||
<Catalog name={nameCatalog}
|
||||
<CatalogSC name={nameCatalog}
|
||||
headers={headers}
|
||||
items={items}
|
||||
onAdd={handleAdd}
|
||||
@ -103,6 +103,6 @@ export default function Categories(props) {
|
||||
onClose={reset}
|
||||
onBtnAdd={reset}
|
||||
form={form}>
|
||||
</Catalog>
|
||||
</CatalogSC>
|
||||
</div>
|
||||
}
|
37
front/src/components/CountStudInCategory.jsx
Normal file
37
front/src/components/CountStudInCategory.jsx
Normal file
@ -0,0 +1,37 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import DataService from '../services/DataService';
|
||||
import CatalogForGroup from "./CatalogForGroup.jsx";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import GroupedStudAndCategoryDto from "../models/GroupedStudAndCategoryDto";
|
||||
|
||||
export default function CountStudInCategory(props) {
|
||||
|
||||
const headers = [
|
||||
{name: 'categoryName', label: "Название"},
|
||||
{name: 'studentsCount', label: "Студенты"},
|
||||
];
|
||||
|
||||
const nameCatalog = "Количество студентов в категории";
|
||||
|
||||
const url = '/categoryStudent/groupbycategory';
|
||||
|
||||
const [items, setItems] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
loadItems();
|
||||
}, []);
|
||||
|
||||
function loadItems() {
|
||||
DataService.readAll(url, (data) => new GroupedStudAndCategoryDto(data))
|
||||
.then(data => setItems(data));
|
||||
}
|
||||
|
||||
return <div className="container-lg pt-5 min-vh-100">
|
||||
<CatalogForGroup name={nameCatalog}
|
||||
headers={headers}
|
||||
items={items}>
|
||||
</CatalogForGroup>
|
||||
</div>
|
||||
|
||||
|
||||
}
|
@ -3,7 +3,7 @@ import Form from 'react-bootstrap/Form';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import { useState, useEffect } from 'react';
|
||||
import DataService from '../services/DataService';
|
||||
import Catalog from "./Catalog.jsx";
|
||||
import CatalogSC from "./CatalogSC.jsx";
|
||||
export default function Students(props) {
|
||||
const headers = [
|
||||
{name: 'surname', label: "Фамилия"},
|
||||
@ -101,7 +101,7 @@ export default function Students(props) {
|
||||
</Form>
|
||||
|
||||
return <div className="container-lg pt-5 min-vh-100">
|
||||
<Catalog name={nameCatalog}
|
||||
<CatalogSC name={nameCatalog}
|
||||
headers={headers}
|
||||
items={items}
|
||||
onAdd={handleAdd}
|
||||
@ -110,6 +110,6 @@ export default function Students(props) {
|
||||
onClose={reset}
|
||||
onBtnAdd={reset}
|
||||
form={form}>
|
||||
</Catalog>
|
||||
</CatalogSC>
|
||||
</div>
|
||||
}
|
8
front/src/components/commons/ItemTableForGroup.jsx
Normal file
8
front/src/components/commons/ItemTableForGroup.jsx
Normal file
@ -0,0 +1,8 @@
|
||||
export default function ItemTableForGroup(props) {
|
||||
|
||||
return <tr key={props.item.id}>
|
||||
{
|
||||
props.headers.map((header) => <td key={`${header.name}_${props.item.id}`}>{props.item[header.name]}</td>)
|
||||
}
|
||||
</tr>
|
||||
}
|
18
front/src/components/commons/ItemTableSC.jsx
Normal file
18
front/src/components/commons/ItemTableSC.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import Button from 'react-bootstrap/Button';
|
||||
export default function ItemTableSC(props) {
|
||||
function edit() {
|
||||
props.onEdit(props.item.id);
|
||||
}
|
||||
function remove() {
|
||||
props.onDelete(props.item.id);
|
||||
}
|
||||
|
||||
return <tr key={props.item.id}>
|
||||
{
|
||||
props.headers.map((header) => <td key={`${header.name}_${props.item.id}`}>{props.item[header.name]}</td>)
|
||||
}
|
||||
{props.isOnlyView || <td key={`controls_${props.item.id}`}>
|
||||
<Button variant="btn btn-outline-primary" onClick={edit}>Редактировать</Button>
|
||||
<Button variant="btn btn-outline-danger" onClick={remove}>Удалить</Button></td>}
|
||||
</tr>
|
||||
}
|
26
front/src/components/commons/TableForGroup.jsx
Normal file
26
front/src/components/commons/TableForGroup.jsx
Normal file
@ -0,0 +1,26 @@
|
||||
import ItemTableForGroup from './ItemTableForGroup';
|
||||
|
||||
export default function TableForGroup(props) {
|
||||
|
||||
return <div >
|
||||
<table className={`table table-hover`}>
|
||||
<thead>
|
||||
<tr>
|
||||
{
|
||||
props.headers.map((header) => <th key={header.name}>{header.label}</th>)
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
props.items.map((item, index) =>
|
||||
<ItemTableForGroup
|
||||
key={index}
|
||||
headers={props.headers}
|
||||
item={item}
|
||||
isOnlyView={props.isOnlyView}/>)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
35
front/src/components/commons/TableSC.jsx
Normal file
35
front/src/components/commons/TableSC.jsx
Normal file
@ -0,0 +1,35 @@
|
||||
import ItemTableSC from './ItemTableSC';
|
||||
export default function TableSC(props) {
|
||||
function edit(itemId) {
|
||||
props.onEdit(itemId)
|
||||
}
|
||||
function remove(itemId) {
|
||||
props.onDelete(itemId);
|
||||
}
|
||||
|
||||
return <div >
|
||||
<table className={`table table-hover`}>
|
||||
<thead>
|
||||
<tr>
|
||||
{
|
||||
props.headers.map((header) => <th key={header.name}>{header.label}</th>)
|
||||
}
|
||||
{props.isOnlyView || <th key='controls'>Элементы управления</th>}
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
props.items.map((item, index) =>
|
||||
<ItemTableSC
|
||||
key={index}
|
||||
headers={props.headers}
|
||||
item={item}
|
||||
onDelete={remove}
|
||||
onEdit={edit}
|
||||
isOnlyView={props.isOnlyView}/>)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
export default class Category {
|
||||
constructor(data) {
|
||||
this.id = data?.id;
|
||||
this.name = data?.name || '';
|
||||
this.name = data?.name || '';
|
||||
}
|
||||
}
|
7
front/src/models/GroupedStudAndCategoryDto.js
Normal file
7
front/src/models/GroupedStudAndCategoryDto.js
Normal file
@ -0,0 +1,7 @@
|
||||
export default class GroupedStudAndCategoryDto {
|
||||
constructor(data) {
|
||||
this.Id = data?.Id;
|
||||
this.categoryName = data?.categoryName;
|
||||
this.studentsCount = data?.studentsCount;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package ru.ulstu.is.cbapp.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import ru.ulstu.is.cbapp.dto.GroupedStudAndCategoryDto;
|
||||
import ru.ulstu.is.cbapp.service.CategoryService;
|
||||
import ru.ulstu.is.cbapp.service.CategoryStudentService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/categoryStudent")
|
||||
public class CategoryStudentController {
|
||||
|
||||
private CategoryStudentService categoryStudentService;
|
||||
|
||||
public CategoryStudentController(CategoryStudentService categoryStudentService) {
|
||||
this.categoryStudentService = categoryStudentService;
|
||||
}
|
||||
|
||||
@GetMapping("/groupbycategory")
|
||||
public List<GroupedStudAndCategoryDto> getGroupedStudAndCategory(){
|
||||
return categoryStudentService.getGroupedStudAndCategory();
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
package ru.ulstu.is.cbapp.dao;
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import ru.ulstu.is.cbapp.dto.GroupedStudAndCategoryDto;
|
||||
import ru.ulstu.is.cbapp.models.Category;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CategoryRepository extends JpaRepository<Category, Long> {
|
||||
|
@ -0,0 +1,19 @@
|
||||
package ru.ulstu.is.cbapp.dao;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import ru.ulstu.is.cbapp.dto.GroupedStudAndCategoryDto;
|
||||
import ru.ulstu.is.cbapp.models.StudentCategories;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface StudentCategoriesRepository extends JpaRepository<StudentCategories, Long> {
|
||||
|
||||
Optional<StudentCategories> findById(Long id);
|
||||
|
||||
@Query("SELECT new ru.ulstu.is.cbapp.dto.GroupedStudAndCategoryDto(cs.category.name,COUNT(cs.student.id))"+
|
||||
"FROM StudentCategories cs "+
|
||||
"group by cs.category.name")
|
||||
List<GroupedStudAndCategoryDto> getGroupedStudAndCategory();
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package ru.ulstu.is.cbapp.dto;
|
||||
|
||||
public class GroupedStudAndCategoryDto {
|
||||
private String categoryName;
|
||||
private Long StudentsCount;
|
||||
|
||||
public GroupedStudAndCategoryDto(String categoryName, Long StudentsCount){
|
||||
this.categoryName=categoryName;
|
||||
this.StudentsCount=StudentsCount;
|
||||
}
|
||||
|
||||
public String getCategoryName() {
|
||||
return categoryName;
|
||||
}
|
||||
|
||||
public void setCategoryId(String categoryName) {
|
||||
this.categoryName = categoryName;
|
||||
}
|
||||
|
||||
public Long getStudentsCount() {
|
||||
return StudentsCount;
|
||||
}
|
||||
|
||||
public void setStudentsCount(Long studentsCount) {
|
||||
StudentsCount = studentsCount;
|
||||
}
|
||||
}
|
@ -2,9 +2,7 @@ package ru.ulstu.is.cbapp.models;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
@Entity
|
||||
public class Category {
|
||||
@ -16,7 +14,7 @@ public class Category {
|
||||
|
||||
//mappedBy - атрибут, указывающий, что классом-владельцем отношений является другой класс
|
||||
@ManyToMany(mappedBy = "categories", cascade = {CascadeType.REMOVE}, fetch = FetchType.EAGER)
|
||||
private List<Student> students = new ArrayList<>();
|
||||
private Set<Student> students = new HashSet<>();
|
||||
|
||||
public Category() {
|
||||
}
|
||||
@ -37,11 +35,11 @@ public class Category {
|
||||
return Id;
|
||||
}
|
||||
|
||||
public List<Student> getStudents() {
|
||||
public Set<Student> getStudents() {
|
||||
return students;
|
||||
}
|
||||
|
||||
public void setStudents(List<Student> students) {
|
||||
public void setStudents(Set<Student> students) {
|
||||
this.students = students;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,9 @@ public class Student {
|
||||
private DrivingSchool drivingSchool;
|
||||
|
||||
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
//@JoinTable(name="CATEGORY_STUDENT",
|
||||
//joinColumns = {@JoinColumn(name="student_id")},
|
||||
//inverseJoinColumns = {@JoinColumn(name="category_id")})
|
||||
private Set<Category> categories = new HashSet<>();
|
||||
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
package ru.ulstu.is.cbapp.models;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name="student_categories")
|
||||
@IdClass(StudentCategoriesId.class)
|
||||
public class StudentCategories {
|
||||
|
||||
public Student getStudent() {
|
||||
return student;
|
||||
}
|
||||
|
||||
public void setStudent(Student student) {
|
||||
this.student = student;
|
||||
}
|
||||
|
||||
public Category getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(Category category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
@Id
|
||||
@ManyToOne
|
||||
@JoinColumn(name="students_id")
|
||||
private Student student;
|
||||
|
||||
@Id
|
||||
@ManyToOne
|
||||
@JoinColumn(name="categories_id")
|
||||
private Category category;
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package ru.ulstu.is.cbapp.models;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class StudentCategoriesId implements Serializable {
|
||||
private Long student;
|
||||
private Long category;
|
||||
|
||||
public Long getStudent() {
|
||||
return student;
|
||||
}
|
||||
|
||||
public void setStudent(Long student) {
|
||||
this.student = student;
|
||||
}
|
||||
|
||||
public Long getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(Long category) {
|
||||
this.category = category;
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package ru.ulstu.is.cbapp.service;
|
||||
|
||||
import ru.ulstu.is.cbapp.dao.CategoryRepository;
|
||||
import ru.ulstu.is.cbapp.dto.GroupedStudAndCategoryDto;
|
||||
import ru.ulstu.is.cbapp.models.Category;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -65,5 +66,4 @@ public class CategoryService {
|
||||
categoryRepository.deleteAll();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
package ru.ulstu.is.cbapp.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import ru.ulstu.is.cbapp.dao.StudentCategoriesRepository;
|
||||
import ru.ulstu.is.cbapp.dto.GroupedStudAndCategoryDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class CategoryStudentService {
|
||||
|
||||
private StudentCategoriesRepository studentCategoriesRepository;
|
||||
|
||||
public CategoryStudentService(StudentCategoriesRepository studentCategoriesRepository) {
|
||||
this.studentCategoriesRepository = studentCategoriesRepository;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<GroupedStudAndCategoryDto> getGroupedStudAndCategory() {
|
||||
return studentCategoriesRepository.getGroupedStudAndCategory();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user