Witam
mam problem z tym że mój select wg. mnie przyjmuje złą wartość, ale do rzeczy, poniżej kod:
SPRING:
Model danych i DTO
@Entity
@Getter
@Setter
public class Offer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private UserEmployee user;
@ManyToOne
@JoinColumn(name = "client_id")
private Client client;
@ManyToOne
private Property property;
private Boolean isBooked;
private Boolean isAvailable;
}
@Getter
@Setter
public class OfferDto {
private Long id;
@NotNull(message = "You have to choose employee")
private Long userId;
@NotNull(message = "You have to choose client")
private Long clientId;
@NotNull(message = "You have to choose property")
private Long propertyId;
private Long reservationId;
private Boolean isBooked;
private Boolean isAvailable;
}
MAPPER I SERWIS
@Service
@RequiredArgsConstructor
public class OfferMapper {
private final PropertyRepository propertyRepository;
private final UserRepository userRepository;
private final ClientRepository clientRepository;
public OfferDto map(Offer offer) {
OfferDto dto = new OfferDto();
dto.setId(offer.getId());
dto.setPropertyId(offer.getProperty().getId());
dto.setClientId(offer.getClient().getId());
dto.setUserId(offer.getUser().getId());
dto.setIsBooked(offer.getIsBooked());
dto.setIsAvailable(offer.getIsAvailable());
return dto;
}
public Offer map(OfferDto dto) {
Offer offer = new Offer();
offer.setId(dto.getId());
Property property = propertyRepository.findById(dto.getPropertyId()).orElseThrow(() -> new ResourceNotFoundException("Property not found"));
offer.setProperty(property);
Client client = clientRepository.findById(dto.getClientId()).orElseThrow(() -> new ResourceNotFoundException("Client not found"));
offer.setClient(client);
UserEmployee userEmployee = userRepository.findById(dto.getUserId()).orElseThrow(() -> new ResourceNotFoundException("Employee not found"));
offer.setUser(userEmployee);
offer.setIsBooked(dto.getIsBooked());
offer.setIsAvailable(dto.getIsAvailable());
return offer;
}
}
@Service
@RequiredArgsConstructor
public class OfferService {
private final OffersRepository offersRepository;
private final UserRepository userRepository;
private final PropertyRepository propertyRepository;
private final ClientRepository clientRepository;
private final OfferMapper offerMapper;
private final ValidationService validationService;
@Transactional
public OfferDto saveOffer(@Valid OfferDto offerDto){
Offer offer = offerMapper.map(offerDto);
validationService.validateData(offer);
offer.setIsAvailable(true);
Offer saved = offersRepository.save(offer);
return offerMapper.map(saved);
}
}
@RestController
@RequestMapping("/api/offers")
@CrossOrigin("*")
@RequiredArgsConstructor
public class OfferController {
private final OfferService offerService;
@PostMapping
public ResponseEntity<OfferDto> saveOffer(@RequestBody @Valid OfferDto offerDto) {
OfferDto saved = offerService.saveOffer(offerDto);
URI uri = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(saved.getId())
.toUri();
return ResponseEntity.created(uri).body(saved);
}
}
Jeżeli chodzi o serwis i kontroler to wrzucam tylko metode odpowiedzialną za dodawanie oferty bo w tym jest kłopot.
KOD REACTA:
import axios from "axios";
class OffersService {
static BASE_URL = "http://localhost:8080/api/offers";
static async addOffer (offerData, token){
try{
const response = await axios.post(`${OffersService.BASE_URL}`, offerData,
{
headers: {Authorization: `Bearer ${token}`}
}
)
return response.data;
}catch(error){
if(error.response && error.response.data){
throw error.response.data
}else{
throw new Error("Adding the offer failed. Please try again")
}
}
}
}
KOMPONENT:
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import OffersService from "../../service/OffersService";
import Notification, { showNotification } from "../alerts/Notification";
import ClientService from "../../service/ClientService";
import PropertyService from "../../service/PropertyService";
import EmployeeService from '../../service/EmployeeService'
function AddOffer() {
const [offerData, setOfferData] = useState({
userId: "",
clientId: "",
propertyId: "",
isBooked: "",
isAvailable: "",
});
const [errors, setErrors] = useState({
userId: "",
clientId: "",
propertyId: "",
});
const [clients, setClients] = useState([]);
const [properties, setProperties] = useState([]);
const [employees, setEmployees] = useState([]);
useEffect(() => {
fetchClients();
fetchProperties();
fetchEmployees();
}, []);
const fetchClients = async () => {
try {
const token = localStorage.getItem("accessToken");
const response = await ClientService.getAllClients(token);
setClients(response.data);
} catch (error) {
console.log(error);
}
};
const fetchProperties = async () => {
try {
const token = localStorage.getItem("accessToken");
const response = await PropertyService.getAllProperties(token);
setProperties(response.data);
} catch (error) {
console.log(error);
}
};
const fetchEmployees = async () => {
try {
const token = localStorage.getItem("accessToken");
const response = await EmployeeService.getAllEmployees(token);
setEmployees(response.data);
} catch (error) {
console.log(error);
}
};
const navi = useNavigate();
const handleInputChange = (e) => {
const { name, value } = e.target;
setOfferData({ ...offerData, [name]: value });
console.log(value);
setErrors({ ...errors, [name]: "" });
};
const handleCheckboxChange = (e) => {
const { name, checked } = e.target;
setOfferData({ ...offerData, [name]: checked });
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
const token = localStorage.getItem("accessToken");
await OffersService.addOffer(offerData, token);
setErrors({});
showNotification("Offer added successfully", "success");
navi("/offers");
} catch (error) {
if (error instanceof Object) {
setErrors(error);
} else {
console.log(error);
}
}
};
return (
<div className="main-content">
<div className="main-content-post">
<h2>Add offer</h2>
{errors.general && <p className="error-msg">{errors.general}</p>}
<form onSubmit={handleSubmit} className="post-form">
<div className="apartment-post-box">
<div className="first-input-box-post">
<div className="input-box-post">
<label htmlFor="">User:</label>
<select
name="userId"
className="select"
value={offerData.userId}
onChange={handleInputChange}
>
<option value="">Select Employee</option>
{employees.map((empl) => (
<option key={empl.id} value={empl.id}>
{empl.firstName}
</option>
))}
</select>
</div>
{errors.userId && <p className="error-msg">{errors.userId}</p>}
<div className="input-box-post">
<label htmlFor="clientId">Client:</label>
<select
name="clientId"
className="select"
value={offerData.clientId}
onChange={handleInputChange}
>
<option value="clientId">Select Client</option>
{clients.map((client) => (
<option key={client.id} value={client.id}>
{client.firstName} {client.lastName}
</option>
))}
</select>
</div>
{errors.clientId && (
<p className="error-msg">{errors.clientId}</p>
)}
<div className="input-box-post">
<label htmlFor="">Property:</label>
<select
name="propertyId"
className="select"
value={offerData.propertyId}
onChange={handleInputChange}
>
<option value="propertyId">Select Property</option>
{properties.map((property) => (
<option key={property.id} value={property.id}>
{property.address}, {property.price} EUR
</option>
))}
</select>
</div>
{errors.propertyId && (
<p className="error-msg">{errors.propertyId}</p>
)}
</div>
<div className="second-input-box-post">
<div className="input-checkbox-group">
<div className="input-box-post">
<label htmlFor="duplex">Booked:</label>
<input
type="checkbox"
id="isBooked"
name="isBooked"
checked={offerData.isBooked}
onChange={handleCheckboxChange}
/>
</div>
<div className="input-box-post">
<label htmlFor="duplex">Available:</label>
<input
type="checkbox"
id="isAvailable"
name="isAvailable"
checked={offerData.isAvailable}
onChange={handleCheckboxChange}
disabled
/>
</div>
</div>
</div>
</div>
<button type="submit" className="my-btn">
Add
</button>
</form>
</div>
</div>
);
}
export default AddOffer;
Sytuacja wygląda tak, gdy miałem ten sam komponent ale ze zwykłymi inputami zamiast selectów i tam wpisywałem np, ID użytkownika ręcznie to wszystko było ok, ale było to mało 'przyjazne', wiec dorzuciłem selecty aby osoba która korzysta sama mógła wybrać spośród dostępnych pracowników czy nieruchomości.
Select jako value przyjmuje offerData.userId, a jednak w konsoli widze ze jest to wartość imienia i nazwiska pracownika jakiego wybrałem. Dlaczego tak się dzieje?
Dostaje przez to błąd po stronie serwera:
2024-05-20T16:37:51.366+02:00 WARN 14976 --- [nio-8080-exec-9] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.lang.Long` from String "John": not a valid `java.lang.Long` value]
Z oczywistych względów bo Spring oczekuje ID a nie imienia i nazwiska.