ошибка Frontend < /strong>
[! [Введите описание изображения здесь] [1]] [1] < /p>
Код: Выделить всё
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/v1/persons")
@CrossOrigin(origins = "http://localhost:4200")
public class PersonController {
@Autowired
private PersonRepository personRepository;
public PersonController(PersonRepository personRepository) {
this.personRepository = personRepository;
}
@RequestMapping(
value = "/api/v1/persons",
produces = "application/json",
consumes = { MediaType.MULTIPART_FORM_DATA_VALUE },
method = RequestMethod.GET)
public ResponseEntity createPerson(
@RequestParam String firstname,
@RequestParam String lastname,
@RequestParam String email,
@RequestParam int age,
@RequestPart(value = "photo", required = false) MultipartFile photo,
@RequestPart(value = "cv", required = false) MultipartFile cv){
try {
Person person = new Person();
person.setFirstname(firstname);
person.setLastname(lastname);
person.setEmail(email);
person.setAge(age);
if (photo != null && !photo.isEmpty()) {
person.setPhoto(photo.getBytes());
}
if (cv != null && !cv.isEmpty()) {
person.setCv(cv.getBytes());
}
System.out.println("Save and upload of the files successfully done");
return ResponseEntity.ok(personRepository.save(person));
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
// Get All Persons
@GetMapping
public List getAllPersons() {
return personRepository.findAll();
}
// Get Person by ID
@GetMapping("/{id}")
public ResponseEntity getPersonById(@PathVariable Long id) {
Optional person = personRepository.findById(id);
return person.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
}
// Update Person
@PutMapping("/{id}")
public ResponseEntity updatePerson(
@PathVariable Long id,
@RequestParam String firstname,
@RequestParam String lastname,
@RequestParam String email,
@RequestParam int age,
@RequestParam(value = "photo", required = false) MultipartFile photo,
@RequestParam(value = "cv", required = false) MultipartFile cv) {
Optional existingPerson = personRepository.findById(id);
if (existingPerson.isPresent()) {
Person person = existingPerson.get();
person.setFirstname(firstname);
person.setLastname(lastname);
person.setEmail(email);
person.setAge(age);
try {
if (photo != null && !photo.isEmpty()) {
person.setPhoto(photo.getBytes());
}
if (cv != null && !cv.isEmpty()) {
person.setCv(cv.getBytes());
}
} catch (IOException e) {
System.out.println("There is something going waring: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
return ResponseEntity.ok(personRepository.save(person));
} else {
return ResponseEntity.notFound().build();
}
}
// Download Person's Photo
@GetMapping("/{id}/photo")
public ResponseEntity getPersonPhoto(@PathVariable Long id) {
Optional person = personRepository.findById(id);
if (person.isPresent() && person.get().getPhoto() != null) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, "image/png")
.body(person.get().getPhoto());
}
return ResponseEntity.notFound().build();
}
// Download Person's CV
@GetMapping("/{id}/cv")
public ResponseEntity getPersonCv(@PathVariable Long id) {
Optional person = personRepository.findById(id);
if (person.isPresent() && person.get().getCv() != null) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, "application/pdf")
.body(person.get().getCv());
}
return ResponseEntity.notFound().build();
}
// Delete Person
@DeleteMapping("/{id}")
public ResponseEntity deletePerson(@PathVariable Long id) {
if (personRepository.existsById(id)) {
personRepository.deleteById(id);
return ResponseEntity.noContent().build();
} else {
return ResponseEntity.notFound().build();
}
}
}< /code>
< /div>
< /div>
< /p>
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.List;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // Disable CSRF
.cors(cors -> cors.configurationSource(corsConfigurationSource())) // Enable CORS
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.POST,"/api/v1/persons/**").permitAll() // Allow all requests to this path
.anyRequest().permitAll() // Allow all requests globally (disable authentication)
);
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("http://localhost:4200"));
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}< /code>
< /div>
< /div>
< /p>
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.4.2
nl.alexandarabski
person-details
0.0.1-SNAPSHOT
person-details
Person details project for Spring Boot
17
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-web
org.postgresql
postgresql
runtime
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-maven-plugin
< /code>
< /div>
< /div>
< /p>
server:
port: 8081
spring:
mvc:
hiddenmethod:
filter:
enabled: true
datasource:
url: jdbc:postgresql://localhost:5333/personsdetails
hikari:
username: sanny
password: sanny13
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
show-sql: true
servlet:
multipart:
enabled: true
max-file-size: 5MB
max-request-size: 10MB
main:
web-application-type: servlet< /code>
< /div>
< /div>
< /p>
export interface Person {
id?: number;
firstname: string;
lastname: string;
email: string;
age: number;
photo: File | null;
cv: File | null;
}< /code>
< /div>
< /div>
< /p>
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Person } from './person';
@Injectable({
providedIn: 'root'
})
export class PersonService {
private baseUrl: string = "http://localhost:8081/api/v1/persons";
//headers: HttpHeaders | { [header: string]: string | string[]; } | undefined;
constructor(private _httpClient: HttpClient) { }
fetchAllPersons(): Observable {
return this._httpClient.get(this.baseUrl).pipe(
map((persons: Person[]) => persons.map(person => ({
...person,
photo: person.photo ? `data:image/png;base64,${person.photo}` : null,
cv: person.cv ? `data:application/pdf;base64,${person.cv}` : null
})))
);
}
createPerson(personData: FormData): Observable {
return this._httpClient.post(`${this.baseUrl}`, personData);
}
updatePerson(personId: number, personData: FormData): Observable {
return this._httpClient.put(`${this.baseUrl} ${personId}`, personData);
}
deletePerson(id: number): Observable {
return this._httpClient.delete(`${this.baseUrl}/${id}`);
}
}< /code>
< /div>
< /div>
< /p>
import { ChangeDetectionStrategy, Component,NgModule, inject } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MAT_DIALOG_DATA, MatDialogActions, MatDialogContent, MatDialogModule, MatDialogRef, MatDialogTitle } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatIconModule } from '@angular/material/icon';
import { Person } from '../person';
import { PersonService } from '../person.service';
import { CommonModule } from '@angular/common';
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-person-form',
imports: [
MatDialogModule,
MatDialogContent,
MatDialogActions,
MatButtonModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
CommonModule,
ReactiveFormsModule,
FormsModule
],
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './person-form.component.html',
styleUrl: './person-form.component.css'
})
export class PersonFormComponent {
personForm: FormGroup;
selectedPhoto: File | null = null;
selectedCv: File | null = null;
readonly dialogRef = inject(MatDialogRef);
data = inject(MAT_DIALOG_DATA);
constructor(private personService: PersonService, private fb: FormBuilder) {
this.personForm = this.fb.group({
id: [this.data?.id || null],
firstname: [this.data?.firstname || '', Validators.required],
lastname: [this.data?.lastname || '', Validators.required],
email: [this.data?.email || '', [Validators.required, Validators.email]],
age: [this.data?.age || null, [Validators.required, Validators.min(1)]]
});
}
onFileSelected(event: any, fileType: string) {
const file = event.target.files[0];
if (file) {
if (fileType === 'photo') {
this.selectedPhoto = file;
} else if (fileType === 'cv') {
this.selectedCv = file;
}
}
}
addOrUpdatePerson() {
const formData = new FormData();
formData.append('firstname', this.personForm.value.firstname);
formData.append('lastname', this.personForm.value.lastname);
formData.append('email', this.personForm.value.email);
formData.append('age', String(this.personForm.value.age)); // Convert age to string
if (this.selectedPhoto) {
formData.append('photo', this.selectedPhoto);
}
if (this.selectedCv) {
formData.append('cv', this.selectedCv);
}
if (this.personForm.value.id) {
// Update existing person (PUT)
this.personService.updatePerson(this.personForm.value.id, formData).subscribe({
next: (response) => {
console.log('Person updated successfully', response);
this.dialogRef.close(response); // Close the dialog with updated data
},
error: (error) => console.error('Error updating person:', error)
});
} else {
// Create new person (POST)
this.personService.createPerson(formData).subscribe({
next: (response) => {
console.log('Person created successfully', response);
this.dialogRef.close(response); // Close the dialog with new data
},
error: (error) => console.error('Error creating person:', error)
});
}
}
}< /code>
< /div>
< /div>
< /p>
import { Component, ViewChild, AfterViewInit, inject } from '@angular/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { MatCardModule } from '@angular/material/card';
import { Person } from '../person';
import { PersonService } from '../person.service';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
import { MatSort, MatSortModule } from '@angular/material/sort';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { PersonFormComponent } from '../person-form/person-form.component';
@Component({
selector: 'app-home',
imports: [
MatFormFieldModule, MatInputModule, MatButtonModule, MatTableModule,
MatCardModule, CommonModule, MatSortModule, MatPaginatorModule, MatDialogModule
],
templateUrl: './home.component.html',
styleUrl: './home.component.css'
})
export class HomeComponent implements AfterViewInit {
person: Person = { // ✅ Add this property
id: 0,
firstname: '',
lastname: '',
email: '',
age: 0,
photo: null,
cv: null
};
displayedColumns: string[] = ['id', 'firstname', 'lastname', 'email', 'age', 'photo', 'cv', 'edit', 'delete'];
dataSource = new MatTableDataSource();
persons: Person[] = [];
filteredPersons: Person[] = [];
readonly dialog = inject(MatDialog);
@ViewChild(MatSort) sort!: MatSort;
@ViewChild(MatPaginator) paginator!: MatPaginator;
constructor(private personService: PersonService, private sanitizer: DomSanitizer) {}
ngAfterViewInit(): void {
this.loadPersons();
}
loadPersons(): void {
this.personService.fetchAllPersons().subscribe((data) => {
this.persons = data;
this.dataSource = new MatTableDataSource(this.persons);
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
});
}
searchPerson(input: string): void {
this.filteredPersons = this.persons.filter(item =>
item.firstname.toLowerCase().includes(input.toLowerCase()) ||
item.lastname.toLowerCase().includes(input.toLowerCase()) ||
item.email.toLowerCase().includes(input.toLowerCase()) ||
item.age.toString().includes(input)
);
this.dataSource = new MatTableDataSource(this.filteredPersons);
}
openDialog(person?: Person): void {
const dialogRef = this.dialog.open(PersonFormComponent, {
data: person
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
this.loadPersons();
}
});
}
deletePerson(id: number): void {
const isConfirmed = window.confirm('Are you sure you want to delete?');
if (isConfirmed) {
this.personService.deletePerson(id).subscribe(() => {
this.persons = this.persons.filter(item => item.id !== id);
this.dataSource.data = this.persons;
});
}
}
}< /code>
< /div>
< /div>
< /p>
Close
Person Form
Upload Photo
Upload CV
Submit
Cancel
< /code>
< /div>
< /div>
< /p>
Full Stack wiht Angular 19, SpringBoot and Docker[/b]
Add +
Id
{{person.id}}
First Name
{{person.firstname}}
Last Name
{{person.lastname}}
Email
{{person.email}}
Age
{{person.age}}
Photo
CV
Download CV
Edit
Edit
Delete
Delete
Подробнее здесь: https://stackoverflow.com/questions/794 ... tsupported