Цей веб-додаток створено за допомогою SpringBoot, Java, Node.js, React
Щасливого копіювання та вставлення.
package com.sundaran.spring_boot_rest.model;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
@Entity
public class JobPost {
@Id
private int postId;
private String postProfile;
private String postDesc;
private int reqExperience;
private List postTechStack;
}
package com.sundaran.spring_boot_rest.repo;
import com.sundaran.spring_boot_rest.model.JobPost;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface JobRepo extends JpaRepository{
List findByPostProfileContainingOrPostDescContaining(String postProfile,String postDesc);
}
package com.sundaran.spring_boot_rest;
import com.sundaran.spring_boot_rest.model.JobPost;
import com.sundaran.spring_boot_rest.service.JobService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@CrossOrigin(origins = "http://localhost:3000")
public class JobRestController {
@Autowired
private JobService service;
@GetMapping(path="jobPosts",produces = {"application/json"})
public List getAllJobs(){
return service.getAllJobs();
}
@GetMapping("jobPost/{postId}")
public JobPost getJob(@PathVariable int postId){
return service.getJob(postId);
}
@GetMapping("jobPost/keyword/{keyword}")
public List searchByKeyword(@PathVariable("keyword") String keyword){
return service.search(keyword);
}
@PostMapping(path="jobPost",consumes = "application/json")
public JobPost addJob(@RequestBody JobPost jobPost){
service.addJob(jobPost);
return service.getJob(jobPost.getPostId());
}
@PutMapping("jobPost")
public JobPost updateJob(@RequestBody JobPost jobPost){
service.updateJob(jobPost);
return service.getJob(jobPost.getPostId());
}
@DeleteMapping("jobPost/{postId}")
public String deleteJob(@PathVariable int postId){
service.deleteJob(postId);
return "Deleted";
}
@GetMapping("load")
public String loadData(){
service.load();
return "success";
}
}
package com.sundaran.spring_boot_rest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootRestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootRestApplication.class, args);
}
}
spring.application.name=spring-boot-rest
spring.datasource.url=jdbc:postgresql://localhost:5433/sundaran
spring.datasource.username=postgres
spring.datasource.password=
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpl.show-sql=true
import React, { useState, useEffect } from "react";
import {
AppBar,
Toolbar,
Box,
Card,
Grid,
Typography,
Button,
TextField,
IconButton,
Container,
Fab,
Drawer,
Divider,
} from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline";
import DeleteIcon from "@mui/icons-material/Delete";
import EditIcon from "@mui/icons-material/Edit";
import CloseIcon from "@mui/icons-material/Close";
import axios from "axios";
const Search = () => {
const [posts, setPosts] = useState([]);
const [newPost, setNewPost] = useState({
postId: "",
postProfile: "",
postDesc: "",
reqExperience: "",
postTechStack: [],
});
const [searchKeyword, setSearchKeyword] = useState("");
const [editMode, setEditMode] = useState(false);
const [drawerOpen, setDrawerOpen] = useState(false);
const fetchAllPosts = async () => {
try {
const response = await axios.get("http://localhost:8080/jobPosts");
setPosts(response.data);
} catch (error) {
console.error("Помилка при отриманні вакансій:", error);
}
};
const fetchFilteredPosts = async (keyword) => {
try {
const response = await axios.get(
`http://localhost:8080/jobPost/keyword/${keyword}`
);
setPosts(response.data);
} catch (error) {
console.error("Помилка при отриманні фільтрованих вакансій:", error);
}
};
const deletePost = async (postId) => {
try {
await axios.delete(`http://localhost:8080/jobPost/${postId}`);
fetchAllPosts();
} catch (error) {
console.error("Помилка при видаленні вакансії:", error);
}
};
const addPost = async () => {
try {
await axios.post("http://localhost:8080/jobPost", newPost);
fetchAllPosts();
resetForm();
setDrawerOpen(false);
} catch (error) {
console.error("Помилка при додаванні вакансії:", error);
}
};
const updatePost = async () => {
try {
await axios.put("http://localhost:8080/jobPost", newPost);
fetchAllPosts();
resetForm();
setDrawerOpen(false);
} catch (error) {
console.error("Помилка при оновленні вакансії:", error);
}
};
const resetForm = () => {
setNewPost({
postId: "",
postProfile: "",
postDesc: "",
reqExperience: "",
postTechStack: [],
});
setEditMode(false);
};
const handleSearchChange = (event) => {
const keyword = event.target.value;
setSearchKeyword(keyword);
if (keyword) {
fetchFilteredPosts(keyword);
} else {
fetchAllPosts();
}
};
useEffect(() => {
fetchAllPosts();
}, []);
return (
{/* AppBar */}
Job Portal
{/* Основний контейнер */}
{/* Пошукова панель */}
),
}}
sx={{
borderRadius: "8px",
backgroundColor: "#fff",
boxShadow: "0px 4px 10px rgba(0, 0, 0, 0.1)",
"& .MuiOutlinedInput-root": {
color: "#333",
"& fieldset": {
borderColor: "#ccc",
},
},
}}
/>
{/* Інструктивний текст */}
Хочете додати вакансію?
Натисніть на плаваючу кнопку нижче, щоб додати нову вакансію до порталу.
{/* Сітка вакансій */}
{posts.map((p) => (
{p.postProfile}
{p.postDesc}
Технології: {p.postTechStack.join(", ")}
Досвід: {p.reqExperience} років
deletePost(p.postId)}
>
{
setEditMode(true);
setNewPost(p);
setDrawerOpen(true);
}}
>
))}
{/* Плаваюча кнопка для додавання вакансії */}
{
setEditMode(false);
setDrawerOpen(true);
}}
>
{/* Бічна панель для додавання/редагування вакансії */}
setDrawerOpen(false)}
sx={{
"& .MuiDrawer-paper": {
width: "400px",
padding: "20px",
backgroundColor: "#fff",
boxShadow: "0px 4px 12px rgba(0, 0, 0, 0.1)",
},
}}
>
{editMode ? "Редагувати вакансію" : "Додати нову вакансію"}
setDrawerOpen(false)}>
setNewPost({ ...newPost, postId: e.target.value })}
fullWidth
disabled={editMode}
sx={{
backgroundColor: "#fff",
boxShadow: "0px 4px 10px rgba(0, 0, 0, 0.1)",
"& .MuiOutlinedInput-root": {
color: "#333",
"& fieldset": {
borderColor: "#ccc",
},
},
}}
/>
setNewPost({ ...newPost, postProfile: e.target.value })}
fullWidth
sx={{ marginTop: "20px" }}
/>
setNewPost({ ...newPost, postDesc: e.target.value })}
fullWidth
sx={{ marginTop: "20px" }}
/>
setNewPost({ ...newPost, reqExperience: e.target.value })}
fullWidth
sx={{ marginTop: "20px" }}
/>
setNewPost({ ...newPost, postTechStack: e.target.value.split(",").map(item => item.trim()) })}
fullWidth
sx={{
marginTop: "20px",
backgroundColor: "#fff",
"& .MuiOutlinedInput-root": {
color: "#333",
},
}}
/>
variant="contained"
color="primary"
onClick={editMode ? updatePost : addPost}
>
{editMode ? "Оновити вакансію" : "Додати вакансію"}
);
};
export default Search;
Перекладено з: [Job App Using React and Spring Boot !](https://sundaran13.medium.com/job-app-using-react-and-spring-boot-89fe0939a1cc)