better way to POST multipart files with JSON data springboot - spring-boot

I am working on a spring boot project, I have a customer model which consists of properties, including image paths which I am storing in the file system or folder and uploading the entire form with image paths in DB, I have successfully implemented my target task however I was wondering if there is a better and nicer way to achieve this, your answers, comments, and feedbacks are appreciated here is my code
Customer model:
public class Customer {
private String contactMode = "Mobile Number";
#Pattern(regexp ="(251|0)[0-9]{9}" , message = "Invalid phone number")
private String phoneNumber; // phone number
private String identityType = "101-ID [0]";
#NotNull(message = "ID number is required")
private String idNumber;
private String countryOfIssue = "XXXXXXX";
#NotNull(message = "Issue date is required")
#PastOrPresent(message = "Issue date cannot be future date")
private Date issueDate;
#Future(message = "Expiry date cannot be in the past or present")
#NotNull(message = "Expiry date is required")
private Date expiryDate;
// storing customerImage , customerID and customerSignature paths in DB
private String customerImage;
private String customerID;
private String customerSignature;
}
Customer Service:
private String path = "C:\Users\User\Desktop\docs\uploaded_files\";
public Customer saveCustomer(Customer customer, MultipartFile customerImage, MultipartFile customerID,
MultipartFile customerSignature) throws Exception {
final String PATH = path + customer.getContactDetail();
Customer phoneNumberExists = customerRepository.findByContactDetail(customer.getContactDetail());
byte[] imageBytes = customerImage.getBytes();
byte[] idBytes = customerID.getBytes();
byte[] signatureBytes = customerSignature.getBytes();
Path customerImagePath = Paths.get
(PATH + "_photo_" + customerImage.getOriginalFilename());
Files.write(customerImagePath, imageBytes);
Path customerIDPath =
Paths.get(PATH + "_ID_" + customerID.getOriginalFilename());
Files.write(customerIDPath, idBytes);
Path customerSignaturePath =
Paths.get(PATH + "_Sign_" + customerSignature.getOriginalFilename() + "");
Files.write(customerSignaturePath, signatureBytes);
if (phoneNumberExists != null) {
throw new PhoneNumberTakenException("Phone number is taken ");
}
customer.setAge(new Date().getYear() - customer.getDateOfBirth().getYear());
customer.setCustomerImage(String.valueOf(customerImagePath));
customer.setCustomerID(String.valueOf(customerIDPath));
customer.setCustomerSignature(String.valueOf(customerSignaturePath));
customer.setFromDate(LocalDate.now());
customer.setStatus(Customer.Status.Submitted);
Customer customerRecord = customerRepository.saveAndFlush(customer);
return customerRecord;
}
Customer Controller : look at how iam passing multipart files and other fields in the controller to service
#PostMapping()
public ResponseEntity<Customer> createCustomer(#Valid #RequestPart("customer") String customer, MultipartFile customerImage, MultipartFile customerID, MultipartFile customerSignature
) throws Exception {
ObjectMapper customerMapper = new ObjectMapper();
Customer savedCustomer = customerMapper.readValue(customer, Customer.class);
Customer customerRecord = customerService.saveCustomer(savedCustomer, customerImage, customerID, customerSignature);
log.debug("inside createCustomer() controller : {}", customerRecord);
return ResponseEntity.status(HttpStatus.CREATED).body(customerRecord);
}
Postman post request to the endpoint:
Postman response :

Related

Spring boot application not accepting ID of incoming POST request

I have an existing system that uses string based unique IDs for users and I want to transfer that System into a Spring boot application. I want to creat a user so I send a POST request with the following content:
As you can see, the id gets ignored.
This is my Spring code for the user class:
#PostMapping("/user")
ResponseEntity addUser(User receivedUser) {
Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
logger.info("Empfangener User: " + receivedUser.toString());
try {
User mailCheckUser = userService.getUserByMail(receivedUser.getEmail());
User nameCheckUser = userService.getUserByName(receivedUser.getUsername());
if (mailCheckUser != null){
return new ResponseEntity("Email already exists", HttpStatus.NOT_ACCEPTABLE);
}
if (nameCheckUser != null){
return new ResponseEntity("Username already exists", HttpStatus.NOT_ACCEPTABLE);
}
userService.addUser(receivedUser);
} catch (Exception userCreationError) {
return new ResponseEntity(receivedUser, HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity(receivedUser, HttpStatus.OK);
}
public void addUser(User user) {
userRepository.save(user);
}
And this is my user class:
#Entity
#Table
public class User {
#Id
#Column(unique =true)
private String id;
private #Column(unique =true)
String username;
private #Column(unique =true)
String email;
private #Column(unique =true)
String simpleAuthToken;
private
String password;
/*REDACTED*/
private
boolean isBlocked;
public User(String id, String name, String email, boolean isBlocked) {
this.id = id;
this.username = name;
this.email = email;
this.simpleAuthToken = simpleAuthToken;
this.isBlocked = false;
}
public User() {
}
/*GETTERS AND SETTERS ARE HERE, BUT I CUT THEM FOR SPACING REASONS*/
}
And this is the Spring Output:
My expected outcome would be that Spring would recognize the id and then create a user with the id I provided. Why is the id always null?
EDIT: If I put the ID in a Put or Get Mapping as Path variable, like so:
#PutMapping("/user/{id}")
ResponseEntity updateUser(#PathVariable String id, User receivedUser) {}
then it gets read and recognized, but it will still be null in the receivedUser
First add #RequestBody in the post request body. In the Post request (/test/user) your passing some params but in the method level not received.
If you want receive id from postman then add #RequestParam("id")String id in the method level.
How you generating unique Id by manually or some generators?
And double check user id at the database console level.

Springboot: 415 Unsupported Media Type

These are my headers: Headers
This error cropped up out of nowhere. I've been sending POST requests to my application without error for a while now. My Post method reads:
Controller:
#PostMapping(path = "/generateCredential", consumes="multipart/form-data")
#ApiOperation(value = "User can register using this Api", response = RegisterForPluginResponse.class)
public ResponseEntity<Object> generateCredential(#Valid #RequestBody RegisterForPluginRequest registerForPlugin) {
...
}
dto:
public RegisterForPluginRequest() {
super();
}
public RegisterForPluginRequest(#Email #NotEmpty String clientName, #NotEmpty int packageId, String phone, String email) {
super();
this.clientName = clientName;
this.packageId = packageId;
this.phone = phone;
this.email = email;
}
What could cause a 415 error where previously there was none? I did recently make changes to make changes to my application's SQL table by adding 2 columns, I wonder if this could be the source of my problem?

Spring Rest Docs unable to add Model constraints in request fiels table

I want to use the Contraints of my Dto model in my request fields documentation. When I use auto rest docs it works but then I have a problem with my KeycloakAuthMock. So I won't use auto rest docs as per documentation the requestfields can easily be added.
#Test
#Order(5)
#WithMockKeycloakAuth(authorities = "ROLE_owner")
void createProduct_RealmRoleOwner_HttpStatusCreated() throws Exception {
MvcResult response = mockMvc.perform(post(URL).contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(testProductDto))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.created").isNumber())
.andExpect(jsonPath("$.name").value(testProductDto.getName()))
.andExpect(jsonPath("$.price").value(testProductDto.getPrice()))
.andExpect(jsonPath("$.id").value(1L))
.andDo(document("{methodName}",
Preprocessors.preprocessRequest(),
Preprocessors.preprocessResponse(
ResponseModifyingPreprocessors.replaceBinaryContent(),
ResponseModifyingPreprocessors.limitJsonArrayLength(objectMapper),
Preprocessors.prettyPrint()),
requestFields( fieldWithPath("name").description("Name of the product"),
fieldWithPath("price").description("Price of the new product")),
responseFields(fieldWithPath("id").description("Id of the new product"),
fieldWithPath("name").description("Name of the product"),
fieldWithPath("price").description("Price of the new product"),
fieldWithPath("created").description("Unix timestamp when the product was created")
)))
.andReturn();
Model:
#ApiModel(description = "Data transfer model for a new product.")
public class ProductDto {
#ApiModelProperty(notes = "Name of the new product.")
#NotNull(message = "name must not be null")
#Size(min = 2, max = 10 , message = "Name length min is 2 and max is 10")
private String name;
#ApiModelProperty(notes = "price of the new product")
#NotNull(message = "price must not be null")
#Min(value = 1, message = "price min is 1")
#Max(value = 100, message = "price max is 100")
private Double price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
}
I tried to follow the guide and I added the template. The template is used but I get a Mustache exception that contraints field is not found. As I won't document the constraints by hand who can I make spring rest docs add the constraints provided by my model?

Java: GroupSequenceProvider for Validation, object is null in getValidationGroups method

This is what I am trying to achieve:
I have an update request object and user is allowed to do Partial Updates. But I want to validate the field only if it is in the request body. Otherwise, it is OK to be null. To achieve this, I am using GroupSequenceProvider to let the Validator know what groups to validate. What am I doing wrong here? If there is a blunder, how do I fix it?
Documentation: https://docs.jboss.org/hibernate/validator/5.1/reference/en-US/html/chapter-groups.html#example-implementing-using-default-group-sequence-provider
#GroupSequenceProvider(UpdateUserRegistrationGroupSequenceProvider.class)
public class UpdateUserRegistrationRequestV1 {
#NotBlank(groups = {EmailExistsInRequest.class})
#Email(groups = {EmailExistsInRequest.class})
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE, groups = {EmailExistsInRequest.class})
private String email;
#NotNull(groups = {PasswordExistsInRequest.class})
#Size(min = 8, max = 255, groups = {PasswordExistsInRequest.class})
private String password;
#NotNull(groups = {FirstNameExistsInRequest.class})
#Size(max = 255, groups = {FirstNameExistsInRequest.class})
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE, groups = {FirstNameExistsInRequest.class})
private String firstName;
// THERE ARE GETTERS AND SETTERS BELOW
}
Group Sequence Provider Code:
public class UpdateUserRegistrationGroupSequenceProvider implements DefaultGroupSequenceProvider<UpdateUserRegistrationRequestV1> {
public interface EmailExistsInRequest {}
public interface PasswordExistsInRequest {}
public interface FirstNameExistsInRequest {}
#Override
public List<Class<?>> getValidationGroups(UpdateUserRegistrationRequestV1 updateUserRegistrationRequestV1) {
List<Class<?>> defaultGroupSequence = new ArrayList<Class<?>>();
defaultGroupSequence.add(Default.class);
defaultGroupSequence.add(UpdateUserRegistrationRequestV1.class);
if(StringUtils.hasText(updateUserRegistrationRequestV1.getEmail())) {
defaultGroupSequence.add(EmailExistsInRequest.class);
}
if(StringUtils.hasText(updateUserRegistrationRequestV1.getPassword())) {
defaultGroupSequence.add(PasswordExistsInRequest.class);
}
if(StringUtils.hasText(updateUserRegistrationRequestV1.getFirstName())) {
defaultGroupSequence.add(FirstNameExistsInRequest.class);
}
return defaultGroupSequence;
}
}
I am using Spring MVC, so this is how my controller method looks,
#RequestMapping(value = "/{userId}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void updateUser(#PathVariable("userId") Long userId,
#RequestBody #Valid UpdateUserRegistrationRequestV1 request) {
logger.info("Received update request = " + request + " for userId = " + userId);
registrationService.updateUser(userId, conversionService.convert(request, User.class));
}
Now the problem is, the parameter "updateUserRegistrationRequestV1" in the UpdateUserRegistrationGroupSequenceProvider.getValidationGroups method is null. This is the request object that I am sending in the request body and I am sending email field with it.
What am I doing wrong?
I too went through the same issue ,and hopefully solved it
You just have to check the object is null and put all your conditions inside it.
public List<Class<?>> getValidationGroups(Employee object) {
List<Class<?>> sequence = new ArrayList<>();
//first check if the object is null
if(object != null ){
if (!object.isDraft()) {
sequence.add(Second.class);
}
}
// Apply all validation rules from default group
sequence.add(Employee.class);
return sequence;
}

Sending SMS in MVC3

I am trying to send sms text in my mvc3 application to an sms gateway a but I get error in my application that
"An object reference is required for the non-static field, method, or
property 'UrWeb.SMS.send(string)'"
Reference Controller
SMS.send(ViewBag.Message);
SMS.cs
private const string _user = "XXX";
private const string _pass = "XXX";
private const string _url = "http://sms.com/api/http.php";
private const string Phone="000000000";
public SMS(string _user, string _pass, string _url)
{
user = _user;
pass = _pass;
url = _url;
}
public string send(string Phone, string Message)
{
string strData = SMSGData(Phone, Phone, Message);
return SendSms(url, strData);
}
.........
Any help in this direction will be highly appreciated
Make your method static
public static string send(string Phone, string Message)
{
....

Resources