发送Post请求时出现启动错误,收到不支持的媒体类型415错误



USER CONTROLLER

package com.example.fwitterbackend;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.catalina.User;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.StreamingHttpOutputMessage.Body;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/users")
public class UsersController {
@Autowired
private UserService userService;

@Autowired
private UserRepository userRepository;

@GetMapping
public ResponseEntity<List<Users>> getAllPosts() {
return new ResponseEntity<List<Users>>(userService.allPosts(), HttpStatus.OK);
}

@GetMapping("/{id}")
public ResponseEntity<Optional<Users>> getSinglePost(@PathVariable ObjectId id) {
return new ResponseEntity<Optional<Users>>(userService.singlePost(id), HttpStatus.OK);
}
@GetMapping("/{userId}/all")
public ResponseEntity<List<Users>> findPostsByUserId(@PathVariable String userId) {
return new ResponseEntity<List<Users>>(HttpStatus.OK);
}

@PostMapping("/create")
public ResponseEntity<Users> createUser(@RequestBody Map<String, String> payload) {
return new ResponseEntity<Users>(userService.createUser(null, payload.get("email"), payload.get("firstName"),payload.get("lastName"), payload.get("password"),payload.get("picturePath"), payload.get("occupation"),payload.get("location")), HttpStatus.OK);
}

@PostMapping("/register")
public ResponseEntity<Users> register(@ModelAttribute ObjectId id, User user) {
try {
// String firstName = user.getFullName();
// String lastName = user.getName();
// String email = ((Users) user).getEmail();
String password = user.getPassword();
// String picturePath = ((Users) user).getPicturePath();
// List<String> friends = ((Object) user).getFriends();
String location = ((Users) user).getLocation();
String occupation = ((Users) user).getOccupation();

// String salt = ( (Object) new BCryptPasswordEncoder()).generateSalt(10);
String passwordHash = new BCryptPasswordEncoder().encode(password);

Users newUser = new Users();

Users savedUser = userRepository.save(newUser);

return new ResponseEntity<>(savedUser, HttpStatus.CREATED);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}

}

用户服务
package com.example.fwitterbackend;
import java.util.List;
import java.util.Optional;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
@Service
public class UserService {
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private UserRepository userRepository;

public List<Users> allPosts() {
return userRepository.findAll();
}

public Optional<Users> singlePost(ObjectId id) {
return userRepository.findById(id);
}


public List<Users> findPostsByUserId(ObjectId userId) {
return userRepository.findPostsByUserId(userId);
}

public Users createUser(ObjectId id, String firstName, String lastName, String email, String password, String picturePath, String occupation, String location) {
Users user = userRepository.insert(new Users(id, firstName, lastName, email, password, picturePath, occupation, location ));
mongoTemplate.update(User.class)
.matching(Criteria.where("id").is(id))
.apply(new Update().push("firstName").value(firstName).push("lastName").value(lastName).push("password").value(password).push("picturePath").value(picturePath).push("occupation").value(occupation).push("email").value(email).push("location").value(location))
// .apply(new Update().push("lastName").value(lastName))
// .apply(new Update().push("password").value(password))
.first();
return user;
}



}

REACT COMPONENT FORM

import { useState } from "react";
import {
Box,
Button,
TextField,
useMediaQuery,
Typography,
useTheme,
} from "@mui/material";
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
import { Formik } from "formik";
import * as yup from "yup";
import { useNavigate } from "react-router-dom";
import { useDispatch } from "react-redux";
import { setLogin } from "state";
import Dropzone from "react-dropzone";
import FlexBetween from "components/FlexBetween";
const registerSchema = yup.object().shape({
firstName: yup.string().required("required"),
lastName: yup.string().required("required"),
email: yup.string().email("invalid email").required("required"),
password: yup.string().required("required"),
location: yup.string().required("required"),
occupation: yup.string().required("required"),
picture: yup.string().required("required"),
});
const loginSchema = yup.object().shape({
email: yup.string().email("invalid email").required("required"),
password: yup.string().required("required"),
});
const initialValuesRegister = {
firstName: "",
lastName: "",
email: "",
password: "",
location: "",
occupation: "",
picture: "",
};
const initialValuesLogin = {
email: "",
password: "",
};
const Form = () => {
const [pageType, setPageType] = useState("login");
const { palette } = useTheme();
const dispatch = useDispatch();
const navigate = useNavigate();
const isNonMobile = useMediaQuery("(min-width:600px)");
const isLogin = pageType === "login";
const isRegister = pageType === "register";
const register = async (values, onSubmitProps) => {
// this allows us to send form info with image
const formData = new FormData();
for (let value in values) {
formData.append(value, values[value]);
}
formData.append("picturePath", values.picture.name);
const savedUserResponse = await fetch(
"http://localhost:8080/api/v1/users/create",
{
method: "POST",
body: formData,
}
);
const savedUser = await savedUserResponse.json();
onSubmitProps.resetForm();
if (savedUser) {
setPageType("login");
}
};
const login = async (values, onSubmitProps) => {
const loggedInResponse = await fetch("http://localhost:8080/api/v1/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(values),
});
const loggedIn = await loggedInResponse.json();
onSubmitProps.resetForm();
if (loggedIn) {
dispatch(
setLogin({
user: loggedIn.user,
token: loggedIn.token,
})
);
navigate("/home");
}
};
const handleFormSubmit = async (values, onSubmitProps) => {
if (isLogin) await login(values, onSubmitProps);
if (isRegister) await register(values, onSubmitProps);
};
return (
<Formik
onSubmit={handleFormSubmit}
initialValues={isLogin ? initialValuesLogin : initialValuesRegister}
validationSchema={isLogin ? loginSchema : registerSchema}
>
{({
values,
errors,
touched,
handleBlur,
handleChange,
handleSubmit,
setFieldValue,
resetForm,
}) => (
<form onSubmit={handleSubmit}>
<Box
display="grid"
gap="30px"
gridTemplateColumns="repeat(4, minmax(0, 1fr))"
sx={{
"& > div": { gridColumn: isNonMobile ? undefined : "span 4" },
}}
>
{isRegister && (
<>
<TextField
label="First Name"
onBlur={handleBlur}
onChange={handleChange}
value={values.firstName}
name="firstName"
error={
Boolean(touched.firstName) && Boolean(errors.firstName)
}
helperText={touched.firstName && errors.firstName}
sx={{ gridColumn: "span 2" }}
/>
<TextField
label="Last Name"
onBlur={handleBlur}
onChange={handleChange}
value={values.lastName}
name="lastName"
error={Boolean(touched.lastName) && Boolean(errors.lastName)}
helperText={touched.lastName && errors.lastName}
sx={{ gridColumn: "span 2" }}
/>
<TextField
label="Location"
onBlur={handleBlur}
onChange={handleChange}
value={values.location}
name="location"
error={Boolean(touched.location) && Boolean(errors.location)}
helperText={touched.location && errors.location}
sx={{ gridColumn: "span 4" }}
/>
<TextField
label="Occupation"
onBlur={handleBlur}
onChange={handleChange}
value={values.occupation}
name="occupation"
error={
Boolean(touched.occupation) && Boolean(errors.occupation)
}
helperText={touched.occupation && errors.occupation}
sx={{ gridColumn: "span 4" }}
/>
<Box
gridColumn="span 4"
border={`1px solid ${palette.neutral.medium}`}
borderRadius="5px"
p="1rem"
>
<Dropzone
acceptedFiles=".jpg,.jpeg,.png"
multiple={false}
onDrop={(acceptedFiles) =>
setFieldValue("picture", acceptedFiles[0])
}
>
{({ getRootProps, getInputProps }) => (
<Box
{...getRootProps()}
border={`2px dashed ${palette.primary.main}`}
p="1rem"
sx={{ "&:hover": { cursor: "pointer" } }}
>
<input {...getInputProps()} />
{!values.picture ? (
<p>Add Picture Here</p>
) : (
<FlexBetween>
<Typography>{values.picture.name}</Typography>
<EditOutlinedIcon />
</FlexBetween>
)}
</Box>
)}
</Dropzone>
</Box>
</>
)}
<TextField
label="Email"
onBlur={handleBlur}
onChange={handleChange}
value={values.email}
name="email"
error={Boolean(touched.email) && Boolean(errors.email)}
helperText={touched.email && errors.email}
sx={{ gridColumn: "span 4" }}
/>
<TextField
label="Password"
type="password"
onBlur={handleBlur}
onChange={handleChange}
value={values.password}
name="password"
error={Boolean(touched.password) && Boolean(errors.password)}
helperText={touched.password && errors.password}
sx={{ gridColumn: "span 4" }}
/>
</Box>
{/* BUTTONS */}
<Box>
<Button
fullWidth
type="submit"
sx={{
m: "2rem 0",
p: "1rem",
backgroundColor: palette.primary.main,
color: palette.background.alt,
"&:hover": { color: palette.primary.main },
}}
>
{isLogin ? "LOGIN" : "REGISTER"}
</Button>
<Typography
onClick={() => {
setPageType(isLogin ? "register" : "login");
resetForm();
}}
sx={{
textDecoration: "underline",
color: palette.primary.main,
"&:hover": {
cursor: "pointer",
color: palette.primary.light,
},
}}
>
{isLogin
? "Don't have an account? Sign Up here."
: "Already have an account? Login here."}
</Typography>
</Box>
</form>
)}
</Formik>
);
};
export default Form;

最初的POST请求给了我一个CORS ERRORS和403 &现在它给CORS错误和415

我尝试过的事情

  • 在标题中添加NO CORS模式
  • 将RequestBody更改为ModelAttribute

我将非常感谢任何类型的帮助或反馈,因为这需要这么长的时间来解决

a415表示页面发送的内容类型与控制器期望的内容类型不匹配。

提交的数据是FormData,但接收控制器方法api/v1/users/create - createUser期望json (consumes未设置时默认值)。

试题:

@PostMapping(
path = "/create",
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public ResponseEntity<Users> createUser(@RequestBody Map<String, String> payload) {

MediaType.MULTIPART_FORM_DATA

第一个答案应该也有帮助。

最新更新