Use #RequestBody to receive data from ajax and binding it to 'User', but failed - ajax

I used AJAX to submit data to the spring boot backend with the #RequestBody annotation to accept it. However, when doing that, it showed the followinng error, which confuses me:
Required String parameter 'username' is not present
Console output
Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'username' is not present]
AJAX code
$("#submitBTN").click(
function(){
$.ajax({
type:"post",
async:false,
url:"/user/doSignIn?verification="+$("input[name='verificationCode']").val(),
contentType: "application/json;charset=utf-8",//必须加
data: JSON.stringify({
'username': $("input[name='username']").val(),
'password':$("input[name='password']").val(),
'email': $("input[name='email']").val()
}),
success:function(r){
if(r.code==window.ResponseStatus.OK){
$(window).attr('location',+'/index');
}else{
console.log(r.msg);
}
}
});
}
);
Entity User
#Entity
public class User {
// 自增id
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
// 用户名
#Pattern(regexp = "^.{4,14}$",groups = UserSignUp.class)
#Column(length = 14)
private String username;
// 密码
#Pattern(regexp = "^[0-9a-zA-Z!##$%^&*.]{6,25}$")
#Column(length = 25)
private String password;
// 邮箱
#Email
private String email;
// 电话号码
#Pattern(regexp = "^\\d{11}$",groups = UserSignUp.class)
#Column(length = 11)
private String phoneNumber;
// 所属用户组
private byte userGroup;
RequestHandler code
#PostMapping(value = "/doSignUp")
public FOResponse doSignUp(#RequestBody User user,
BindingResult result,
#RequestParam String verificationCode,
HttpSession session){...}

Related

How can I add properties to the mutation successful response

I am new to graphql-spqr so I hope this is an easy question, however I couldn't find a solution for this, even after a long search.
Hint: In my app, I use the code-first/schema-last approach, which I like about the graphql-spqr, so there is no schema.graphqls loaded from a file.
My User.java starts with this
#Table(name = "users")
#Entity
#Setter
#Getter
#EntityListeners(AuditingEntityListener.class)
public class User {
#Id
#GraphQLQuery(name = "id", description = "A user's id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false, updatable = false)
public Long id;
#GraphQLQuery(name = "firstName", description = "User's first name")
#Column(name = "first_name")
public String firstName;
#GraphQLQuery(name = "lastName", description = "User's last name")
#Column(name = "last_name")
public String lastName;
#GraphQLQuery(name = "email", description = "User's email")
public String email;
#GraphQLQuery(name = "uuid", description = "User's uuid")
//#Type(type = "char")
public String uuid;
//#Type(type = "char")
#Transient
public Company company;
#Column(name = "company")
public Long companyId;
#Transient
public Role role;
#Column(name = "role")
public Long roleId;
#Column(name = "pw")
public String password;
#GraphQLQuery(name = "terms", description = "User accepted terms")
public Boolean terms;
#Transient
public String token;
#CreatedDate
public Instant created;
public String getUuid() {
return this.uuid;
}
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
public String getEmail() {
return this.email;
}
public String getPassword() {
return this.password;
}
}
A user is created by a mutation:
#GraphQLMutation(name = "createUser")
public User createUser (
#GraphQLArgument(name = "firstName") String firstName,
#GraphQLArgument(name = "lastName") String lastName,
#GraphQLArgument(name = "email") String email,
#GraphQLArgument(name = "password") String password,
#GraphQLArgument(name = "company") String company,
#GraphQLArgument(name = "terms") Boolean terms) throws UserExistsException {
... some business logic
... and finally I use the JpaRepository<User, String> to save the user
return userRepository.save(user);
}
This is the query I am sending to the server
{"operationName":"CreateUser","variables":{"firstName":"Chris","lastName":"Rowing","email":"foo54#bar.com","password":"dada","company":"Test 5","terms":true,"source":"start","invitationId":null},"query":"mutation CreateUser($firstName: String!, $lastName: String!, $email: String!, $password: String!, $terms: Boolean!, $company: String) {\n createUser(\n firstName: $firstName\n lastName: $lastName\n email: $email\n password: $password\n terms: $terms\n company: $company\n ) {\n id\n __typename\n }\n}\n"}
The new user gets saved in the DB, everything works fine, and in my Angular client I listen to the success event, and in the inspector there is the following output
{"data":{"createUser":{"id":4,"__typename":"User"}}}
My question
How can I customize the response? For example I need to respond also a JWT token, and maybe hide the id. I have not found a way to do this up to now and any help would be appreciated! Thanks!
For anyone who is experiencing the same newbie problem: This is how I solved it:
I added the token property to the GraphQL query, removed the id property, and added this to the UserService
// Attach a new field called token to the User GraphQL type
#GraphQLQuery
public String token(#GraphQLContext User user) {
return authService.createToken(user.email, user.uuid);
}
It is possible to add external fields to the response without changing the original User.class by using #GraphQLContext

#GetMapping doesn't display CreditCards under username. #PostMapping doesn't create a new card for user, it only updates it

My User Class looks as follows:
#Entity
#Table(name = "Users")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "userID")
private Integer userID;
#Column(name = "username",nullable = false, unique = true)
private String username;
#Column(name = "password")
private String password;
#Column(name = "name")
private String name;
#Column(name = "address")
private String address;
#Column(name = "email")
private String email;
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<CreditCard> creditCard;
//Constructor, Getters and Setters
CreditCard Class looks :
#Entity
#Table(name = "CreditCards")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class CreditCard {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "cardID", nullable = false)
private Integer cardID;
#Column(name = "cardName")
private String cardName;
#Column(name = "cardNumber")
private BigInteger cardNumber;
#Column(name = "expirationDate")
private Integer expirationDate;
#Column(name = "securityCode")
private Integer securityCode;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "user_id", nullable = false)
#JsonIgnore
private User user;
//Constructor, Getters and Setters
CreditCard Resource:
#RestController
#RequestMapping("/geektext/users")
class CreditCardResource {
#Autowired
CreditCardRepository cardsRepository;
#Autowired
UserRepository userRepository;
//Displays CreditCard By Username Search
#GetMapping("/{username}/cards")
public Optional<CreditCard> getCardsByUsername(#PathVariable String username) throws NotFoundException {
if (!userRepository.findByUsername(username).isPresent()){
throw new NotFoundException("User '" + username + "' not found");
}
return cardsRepository.findById(userRepository.findByUsername(username).get().getUserID());
}
//Creates New Card for User
#PostMapping("/{userID}/cards")
public CreditCard loadCard(#PathVariable String userID, #RequestBody CreditCard creditCard) throws NotFoundException {
return userRepository.findByUsername(userID).map(user -> {creditCard.setUser(user);
return cardsRepository.save(creditCard);
}).orElseThrow(() -> new NotFoundException("User '" + userID + "' not found"));
}
}
There is also a UserResource.java , UserRepository (Interface) and CreditCardRepository) but these do not affect the problem I am having. Please how can I fix getting list of cards for User passing username on url. How can user create New/ More than one CreditCard instead of updating the one he has.
You are trying to get a credit-card using your userID
return cardsRepository.findById(userRepository.findByUsername(username).get().getUserID());
Instead, you could search for your credit-card by user. To do this, you should create a method in the credit-card repository interface.
List<CreditCard> findByUser(User user);
Then call this method from your controller
return cardsRepository.findByUser(userRepository.findByUsername(username).get())
The post method has a similar problem. You are trying to get user by username, but passing the userID. Also you set user to your new credit-card, but you don't add a new credit-card to your user. (And change the name of credit-cards variable in the User class to creditCards)
return userRepository.findByUsername(userID).map(user -> {creditCard.setUser(user);
return cardsRepository.save(creditCard);
}).orElseThrow(() -> new NotFoundException("User '" + userID + "' not found"));
This will be much better. Test it yourself and change something if I wrote something wrong
User user = userRepository.findById(userID);
user.getCreditCards().add(creditCard);
creditCard.setUser(user);
userRepository.save(user);
NotFoundException I guess you can handle by yourself.
Update: I had to create an ID for each credit card since if the same ID is assigned on the creation of each new credit card, then program would treat it like if I was the same one that was trying to be updated.

BindingResult in Spring boot not return anything if haserror

I try to test the validation in my service for the fields, but when i put message for response not show the (message & status) in post man
I searched a lot in Stackoverflow no answer for my case
Entity:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false, unique = true)
#NotNull
private String clientName;
#Column(name = "date_of_birth", nullable = false)
#Temporal(TemporalType.DATE)
/** #JsonFormat(pattern="dd/MM/yyyy") **/
private Date dateOfBirth;
#Column(nullable = false)
#NotNull
private String mobileNumber;
#Column(nullable = false)
#NotNull
#Email(message = "Email should be valid")
private String email;
#Column(nullable = false)
#NotNull
private String address;
#Column(nullable = false)
#NotNull
private String sex;
#NotNull(message = "weight cannot be null")
private Integer weight;
#NotNull(message = "hight cannot be null")
private Integer hight;
#Column(nullable = false)
#NotNull
private String healthNote;
#Column(nullable = false)
#NotNull
private String importantNote;
#Column(nullable = false)
#NotNull
private String personToContact;
#Column(nullable = false)
#NotNull
private String relation;
#Column(nullable = false)
#NotNull
private String phoneNumber;
Controller:
#PostMapping("/uploadProfileClient")
public ResponseEntity<?> uploadMultipartFile(#Valid #RequestPart("addClient") String clientNew ,#Valid #RequestPart(value = "image") MultipartFile image,BindingResult result) throws JsonParseException, JsonMappingException, IOException {
clientEntity client = null;
Map<String,Object> response = new HashMap<>();
if(result.hasErrors()) {
List<String> errors = result.getFieldErrors().stream().map(err -> "The field '" + err.getField() +"' "+ err.getDefaultMessage()) .collect(Collectors.toList());
response.put("Errors",errors);
return new ResponseEntity<Map<String,Object>>(response, HttpStatus.BAD_REQUEST);
}
ObjectMapper mapper = new ObjectMapper();
client = mapper.readValue(clientNew, clientEntity.class);
client.setImage(image.getBytes());
try {
clientService.save(client);
} catch ( DataAccessException e) {
response.put("message", "Error when inserting into the database");
response.put("error", e.getMessage().concat(": ").concat(e.getMostSpecificCause().getMessage()));
return new ResponseEntity<Map<String,Object>>(response,HttpStatus.INTERNAL_SERVER_ERROR);
}
response.put("message", "the client data has been created successfully!");
response.put("client", client);
return new ResponseEntity<Map<String,Object>>(response,HttpStatus.CREATED);
}
I will send data as json and file, the response no show in postman, please i need answer.
The problem is pretty straight forward, the Weight attribute accepts Integer but you are sending "weight":"as", that is why you are getting Deserialize issue correct it.
Try with below, dummy data
{
"clientName":"foo",
"dateOfBirth":"2020-03-19",
"mobileNumber":"9911",
"email":"asd#email.com",
"address":"sa",
"sex":"m",
"weight":"1",
"hight":"12",
"healthNote":"note",
"importantNote":"imp",
"personToContact":"myself",
"relation":"single",
"phoneNumber":"mynumber"
}
And also you don't have to manually convert the string to Entity using ObjectMapper. Spring can handle that so change the controller
#PostMapping("/uploadProfileClient")
public ResponseEntity<?> uploadMultipartFile(#Valid #RequestPart("addClient") ClientEntity clientNew ,#Valid #RequestPart(value = "image") MultipartFile image,BindingResult result) throws JsonParseException, JsonMappingException, IOException {
//now you can save clientEntity directly
client.setImage(image.getBytes());
clientService.save(client);
//your logic
}
Update
How to request from PostMan

spring mvc and ajax get 400 error

My model as below and add use the spring mvc.
#Entity
#Table(name="audit_report")
public class AuditReport implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "audit_report_id")
private int auditReportId;
#ManyToOne(fetch=FetchType.LAZY,optional = false,cascade=CascadeType.ALL)
#JoinColumn(name="audit_factory_id")
private AuditFactory auditFactory;
#Column(name = "report_id")
private String reportId;
#Column(name = "editor")
private String editor;
#Column(name = "engineer_name")
#NotNull
private String engineerName;
#Column(name="service_date")
#DateTimeFormat(pattern="MM/dd/yyyy")
private Date serviceDate;
#Column(name="audit_date")
#DateTimeFormat(pattern="MM/dd/yyyy")
private Date auditDate;
#OneToMany(cascade = CascadeType.ALL ,fetch = FetchType.LAZY, mappedBy = "auditReport")
#Fetch(FetchMode.SUBSELECT)
private List<Printer> printers;
controller as below,it will get the model and save it.
#ResponseBody
#RequestMapping(value = "/saveAuditReport",method = RequestMethod.POST)
public Map<String,String> newAuditReport(HttpServletRequest request,#RequestBody AuditReport report){
ajax, it get the 400 error if add the serviceDate and it will ok after remove the serviceDate
$.ajax({
type:"post",
url:"<%=path%>/audit/saveAuditReport.do",
contentType : 'application/json; charset=utf-8',
data:JSON.stringify({'serviceDate':pnDate,'engineerName':engineer,'reportId':reportId,"auditReportId":auditReportId,"printers":array,"auditFactory":{"auditFactoryId":factoryId}}),
dataType:'json',
success:function(data, textStatus){
if(data!=null){
if(data.error==null){
layer.msg(data.ok,1,9);
layer.close(pageii);
searchReportById(factoryId,obj);
}else{
layer.msg(data.error);
}
}
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
}
});
ajax, it get the 400 error if add the serviceDate and it will ok after remove the serviceDate
First of all, Your model should have setters and getters. Then, One possible problem is auditReportId field in your model. You used #Id and #GeneratedValue annotations for it. This means that the auditReportId should not be provided by user and hibernate will generate it automatically. But you assigned it manually. So you should remove "auditReportId":auditReportId part from your json data. Try this and if problem not resolved, post exact exception stack trace for better helping.
You have date parsing error ... so add #JsonSerialize(using = DateSerializer.class) annotation above your date field in your model class
#DateTimeFormat(pattern="MM/dd/yyyy")
#JsonSerialize(using = DateSerializer.class)
private Date serviceDate;

Spring MVC 3.1 : how to map JSON from a PUT request body?

I know this question has been asked a gazillion times, but I still cannot find a solution to my problem, which basically boils down to JSON deserialization from a PUT request.
I've already added HiddenHttpMethodFilter as a filter.
org.codehaus.jackson.jackson-mapper-lgpl is in the classpath.
Here is the client part:
$.ajax({
url: '/occurrence',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify({id:id,startDate:startDate, endDate:endDate, frequencyType:frequency})
})
Here is the controller part:
#Controller
#RequestMapping("/occurrence")
public class OccurrenceController {
private static final String COMMAND = "eventCommand";
#Autowired
private PersistenceCapableOccurrence occurrenceDao;
#Autowired
private PersistenceCapableFrequencyType frequencyTypeDao;
#InitBinder(COMMAND)
public void customizeConversions(final WebDataBinder binder) {
DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm");
df.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(df, true));
EntityConverter<FrequencyType> frequencyTypeEntityConverter = new EntityConverter<FrequencyType>(frequencyTypeDao, FrequencyType.class, "findByValue", String.class);
((GenericConversionService) binder.getConversionService()).addConverter(frequencyTypeEntityConverter);
}
#RequestMapping(method = PUT, consumes = "application/json")
#ResponseBody
public Long saveOccurrence(#RequestBody Occurrence occurrence) {
return occurrenceDao.saveOrUpdate(occurrence);
}
}
Here are my two domain classes (Occurrence and FrequencyType):
public class Occurrence {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", nullable = false)
private long id;
#NotNull
#Column(name = "start_date")
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime startDate;
#Column(name="end_date")
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime endDate;
#ManyToOne
#JoinColumn(name = "frequency_type", nullable = false)
private FrequencyType frequencyType;
/* C-tor (1 with [start,end,freq], another with [start,freq]), getters (no setters) */
}
#Entity
#Table(name = "frequency_types")
public class FrequencyType {
public enum FrequencyTypeValues {
ONCE, DAILY, WEEKLY, MONTHLY, YEARLY;
}
private String value;
public FrequencyType() {}
public FrequencyType(FrequencyTypeValues value) {
this.value = value.name();
}
#Id
#Column(name = "value")
public String getValue() {
return value;
}
public void setValue(String value) {
//validates value against the enumerated/allowed values (ie throws exceptions if invalid value)
FrequencyTypeValues.valueOf(value.toUpperCase());
this.value = value;
}
}
All I get at the end is a 400 response.
Example :
PUT Request
{"id":"","startDate":"20/10/2012 17:32","endDate":"","frequencyType":"YEARLY"}
Response
"NetworkError: 400 Bad Request - http://localhost:9999/occurrence"
Thanks in advance for your help !
Rolf

Resources