I am learning how to write REST APIs! How can I store form values into a text file, using rest calls?
index.html
<form action="rest/product/adddata" method="post">
Enter Id:<input type="text" name="id"/><br/><br/>
Enter Name:<input type="text" name="name"/><br/><br/>
Enter Price:<input type="text" name="price"/><br/><br/>
<input type="submit" value="Add Product"/>
</form>
service.java
#Path("/product")
public class ProductService{
#POST
#Path("/adddata")
public Response addUser(
#FormParam("id") int id,
#FormParam("name") String name,
#FormParam("price") float price) {
return Response.status(200)
.entity(" Product added successfuly!<br> Id: "+id+"<br> Name: " + name+"<br> Price: "+price)
.build();
}
}
I want to add value of id, name and price to a file. Where do I need to write function for adding data to file?
write code into
public Response addUser(
#FormParam("id") int id,
#FormParam("name") String name,
#FormParam("price") float price) {
saveFile(id,name,price);
return Response.status(200)
.entity(" Product added successfuly!<br> Id: "+id+"<br> Name: " + name+"<br> Price: "+price)
.build();
}
write code into saveFile to save into file
The best approach for doing this will be to create another class which can write and read from files. And inject that class in this rest endpoint.
Because The direct code in rest endpoint class should be to handle request not to write files
class FormSynchronizer {
public static final File FORM_BASE = new File(...); // The location of directory which will contain all these files
public void storeFile(Map map, String fileName){
File toStoreFile = new File(FORM_BASE, fileName);
/* Write code to store file */
}
}
Inject this class in your rest endpoint class
public class ProductService{
#Inject FormSynchronizer formSynchronizer;
#POST
#Path("/adddata")
public Response addUser(
#FormParam("id") int id,
#FormParam("name") String name,
#FormParam("price") float price) {
Map<String, Object> data = new HashMap<>();
data.put("id", id);
/* put all data you want to store in this map */
formSynchronizer.storeForm(data, "FORM_" + new Date().getTime()); // I used current time prefixed with 'FORM_' string as file name
return Response.status(200)
.entity(" Product added successfuly!<br> Id: "+id+"<br> Name: " + name+"<br> Price: "+price)
.build();
}
}
Use jackson to Convert Map Object to JSON file and vice-versa.
map to / from json file
Related
Let's consider following scenario:
I need to upload very large file, other than that I need the name, version and author.
I have created the following endpoint:
#PostMapping(path = "/upload", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> upload(#RequestBody MyClass myClass) {
//do the upload using the content received as InputStream and return success
}
The MyClass.java:
public class MyClass {
private String name;
private String version;
private String author;
private InputStream fileContent;
// constructor, getters and setters
}
Example request body:
{
"name": "article",
"version": "1",
"author": "John Smith"
"fileContent": "ZmlsZUNvbnRlbnQg" //base64 encoded tgz/zip
}
So the whole case is to save the name,version and author e.g. in database,
and then use the fileContent InputStream to stream it somewhere (as it is too big to have it as bytearray).
Is something like that possible in spring?
All help appreciated!
I have this function for uploading videos to a directory in my intellij workspace.
#RequestMapping(method = RequestMethod.POST, path = "/projects/save/video")
public String uploadVideo(#RequestParam("file") MultipartFile file, #ModelAttribute Project project) throws InterruptedException {
// check if file is empty
if (file.isEmpty()) {
System.out.println("No file");
return "redirect:/user/projects";
}
// normalize the file path
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
// save the file on the local file system
try(InputStream inputStream = file.getInputStream()) {
Path path = Paths.get(VID_UPLOAD_DIR + fileName);
Files.copy(inputStream, path, StandardCopyOption.REPLACE_EXISTING);
File directory = new File(CLASS_DIR);
if (! directory.exists()) {
directory.mkdir();
}
Path classPath = Paths.get(CLASS_DIR + fileName);
Files.copy(path, classPath, StandardCopyOption.REPLACE_EXISTING);
}
catch (IOException e) {
e.printStackTrace();
}
String part="../videos/"+fileName;
System.out.println(file.getSize() + " <---[]---> " + part);
member.setVideo(part);
MemberDB.projects.get(0).setTitle(project.getTitle());
MemberDB.projects.get(0).setDescription(project.getDescription());
MemberDB.projects.get(0).setLanguage(project.getLanguage());
MemberDB.projects.get(0).setTechnology(project.getTechnology());
MemberDB.projects.get(0).setVideoName(project.getVideoName());
return "redirect:/user/projects";
}
Template (using thymeleaf) looks like this
<form action="#" th:action="#{/projects/save/video}" name="subform" method="post" id="addProject" th:object="${project}" enctype="multipart/form-data">
<h2 class="exempt" style="border:none;">Add project</h2>
<input class="exempt" th:field="*{title}" type="text">
<textarea class="exempt" th:field="*{description}" rows="4"></textarea>
<input class="exempt" type="hidden" th:field="*{videoName}" id="setVidName">
<input class="exempt" type="file" id="vidName" accept="video/mp4" name="file" onchange="setNameVar(this);">
<button class="exempt" type="button" onclick="submitForm();">Save project</button>
</form>
And in your application properties
spring.servlet.multipart.max-file-size=200MB
spring.servlet.multipart.max-request-size=200MB
spring.servlet.multipart.enabled=true
Hi guys new to spring and was wondering why this does work like I though it would. So I have a project model which has a name(a string) and a user(a user object). So I store it mysql and want to retrieve a project base on those two fields and i want to display the project on page which I did already(but only base on user). So add a new thing where I'm using a search bar for input for name. So when the page first load, there isn't any input so it should just retrieve all projects base of user. So I made name (required = false). However, it doesn't show all the projects only base on user(Nothing shows). It only something shows when I enter like a name into search bar.
<form class="form-inline mt-5 my-lg-0" action="/myWork">
<input type="text" class="form-control" name="name" placeholder="Search Project" />
<input type="submit" value="Search" class="btn btn-primary"/></form>
public interface ProjectRepository extends JpaRepository<Project, Integer> {
#Override
List<Project> findAll();
public List<Project> findByUser(User user);
public List<Project>findByUserAndName(User user,String name);
public List<Project> findByType(String type);
}
//Get a project base on user and project name
public List<Project> getProjectByUserandName(Authentication authentication,String name) {
User user = authenticationService.getPrincipal(authentication);
return projectRepo.findByUserAndName(user,name);
}
#GetMapping("/myWork")
public ModelAndView showUserProject(Authentication authentication, #RequestParam(required = false) String name) {
ModelAndView modelAndView = new ModelAndView();
List<Project> projects = new ArrayList<Project>();
try {
projects = projectService.getProjectByUserandName(authentication,name);
System.out.println(projects);
Collections.sort(projects, new customComparator());
} catch (Exception e) {
e.printStackTrace();
}
modelAndView.addObject("projects", projects);
return modelAndView;
}
Handle Empty case of name in getProjectByUserandName.
Instead of
return projectRepo.findByUserAndName(user,name);
Use this :
if(StringUtils.isEmpty(name))
return projectRepo.findByUser(user);
else
return projectRepo.findByUserAndName(user,name);
Hello I am new to web services.
I am able to create simple web service which accept input string and return another string using eclipse.
But when it comes to JSONObject i am facing problems,while invoking web service
public class HelloWorld {
private int rowNumber;
public byte[] readJSON(JSONObject jsonObject ) throws Exception
{
rowNumber=0;
File excelFile = new File("Test2.xlsx");
OutputStream outStream = new FileOutputStream(excelFile);
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("TestSheet");
XSSFRow row ;
XSSFCell cell;
JSONArray msg = (JSONArray) jsonObject.get("messages");
Iterator<String> iterator = msg.iterator();
while (iterator.hasNext()) {
row = sheet.createRow(rowNumber);
cell= row.createCell(0);
cell.setCellValue(iterator.next());
rowNumber=rowNumber+1;
}
workbook.write(outStream);
outStream.close();
Path path = Paths.get("Test2.xlsx");
byte[] data = Files.readAllBytes(path);
return data;
}
public float addValue(float value) {
return (value + 10);
}
}
so help me to consume the web service.
SimpleDeserializer encountered a child element, which is NOT expected, in something it was trying to deserialize. this error i am getting when i try to invoke client. and another thing input parameter as JSONObject is allowed?
You can use the package Package javax.ws.rs.
import javax.ws.rs.*;
Here would be a short of example of the library in action:
Here is the HTML:
<div>
Welcome and happy <span id="today"></span>.
What's your name?
<input id="name" type="text" autofocus />
<button id="submit" onclick="greet()">Submit</button>
</div>
<div id="greet">
<!-- greeting goes here -->
</div>
<script>
// fills in <span id="today">...</span> with today's day of the week
// returned from /rest/today server endpoint
function today() {
$.get("/rest/today", function(theday) {
$("#today").text(theday);
});
};
// fills in <div id="greeting">...</div> with the greeting
// returned from calling the /rest/hello?name=... server endpoint
// with the name from the input text box
function greet() {
var thename = $("#name").val();
$.get("/rest/hello", { name: thename }, function(thehello) {
$("#greet").text(thehello);
})
.fail(function(jqXHR, textStatus, errorThrown) {
// displays server error message, e.g. if called with empty name
$("#greet").text(textStatus + ": " + errorThrown);
});
};
$(today); // execute today() after DOM is ready, see https://api.jquery.com/ready/
</script>
</body>
</html>
With corresponding java code:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
/**
* REST service that greets requests.
*
* This is a "root resource class" as explained in
* https://jersey.java.net/documentation/latest/jaxrs-resources.html
*/
#Path("/")
public class HelloService {
#GET
#Path("/today")
public String today() {
return DayOfWeek.today();
}
#GET
#Path("/hello")
public Response hello(#QueryParam("name") String name) {
if (name == null || name.isEmpty()) {
return Response.status(Response.Status.BAD_REQUEST).build();
} else {
return Response.ok("hello " + name).build();
}
}
}
In order to work with JSON objects, you'll need to use Gson.toJson(). Do something along the lines of this:
String json = new Gson().toJson(some_object);
return Response.ok(json, MediaType.APPLICATION_JSON).build();
I hope this was helpful!
You can try to use Jackson: very good library in which you define you Java object model class that you can convert to JSON or parse from JSON.
You will find a lot of examples
i have some question about Spring MVC annotation #ModelAttribute.
In first method named as "addProduct" i create Model model and after call model.addAttribute i can use "product" name in jsp file,for example product.getProductPrice.
But in second method named same as first,i added parameter
" #ModelAttribute("product") Product product ",but why??
If i will delete this annotation, my program works as same as before,please explain me)
Thank you very much,sorry for my English,i am from Ukraine)
#RequestMapping("/admin/productInventory/addProduct")
public String addProduct(Model model) {
Product product = new Product();
// add default for radio button!
product.setProductCategory("Mobile Phone");
product.setProductCondition("New");
product.setProductStatus("active");
model.addAttribute("product", product);
return "addProduct";
}
#RequestMapping(value = "/admin/productInventory/addProduct", method = RequestMethod.POST)
public String addProduct(#ModelAttribute("product") Product product, HttpServletRequest request) {
productDao.addProduct(product);
MultipartFile productImage = product.getProductImage();
String rootDirectory = request.getSession().getServletContext().getRealPath("/");
System.out.println(rootDirectory);
// product id as the file name
// !!!! TODO
// path = Paths.get(rootDirectory + "/WEB-INF/resources/image/" +
// product.getProductId() + ".png");
path = Paths.get("F:\\Spring\\eMusicStore\\src\\main\\webapp\\WEB-INF\\resources\\images\\"
+ product.getProductId() + ".png");
if (productImage != null && !productImage.isEmpty()) {
try {
productImage.transferTo(new File(path.toString()));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Product image saving failed", e);
}
}
return "redirect:/admin/productInventory";
}
Purpose #ModelAttribute is bind param/properties from request a model object,
say #ModelAttribute("person") Person person in your method, it will bind properties from object such name, age to Person and construct a object out of it. It does not pass anything to your view, it job finishes once the request submitted. Not carried down to the view of that action.
In contrast, when you have Model model you are explicitly constructing an object with property added to its attribute. It will be carried down to your view unlike what #ModelAttribute does above
I have html page which contains 3 file input and 3 text inputs. If I use enctype = multipart/form-data in jsp page I am not able to get the test input form fields. These values always show null. If I remove enctype from post form in jsp, I can get the text field inputs but in this case I cannot upload files. So my question is is it possible to have multiple input fields with file input and if yes how to get the text input field names??
Any help on this is appreciated..
Below is the html code
<html>
<body>
<form method="post" action="upload.jsp" enctype="multipart/form-data">
Office Name: <input type="text" name="officeName" /> <br>
Doc. Description : <input type="text" name="docDesc" /> <br>
Document 1 : <input type="file" name="doc1" /> <br>
Document 2 : <input type="file" name="doc2" /> <br>
Document 3 : <input type="file" name="doc3" /> <br>
Remarks : <input type="text" name="remarks" /> <br>
<br>
<input type="submit" value="submit" />
</form>
And i am retrieving text and file inputs as
strOffficeName=Request.getParameter("officeName");
strDocDescription=Request.getParameter("docDesc");
strDoc1Path=Request.getParameter("doc1");
strDoc2Path=Request.getParameter("doc2");
strDoc3Path=Request.getParameter("doc3");
strRemarks=Request.getParameter("remarks");
I would take a look at Apache Commons FileUpload. It has a User Guide that explains how to get file uploads from your request.
The section "Processing the uploaded items" shows an example how to process both file uploads and text inputs.
Create a class called fileUploader which returns ServletFileUpload object
private FileUploader()
{
}
public static synchronized ServletFileUpload getservletFileUploader(String tempDir, int maxSizeInMB)
{
if(uploader == null)
{
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024 * 1024);
factory.setRepository(new File(tempDir));
uploader = new ServletFileUpload(factory);
uploader.setFileSizeMax(maxSizeInMB * 1024 * 1024);
}
return uploader;
}
Now you can process a request and read all the data. It handles the files uploaded as well as other form data.
protected MultiPartFormData handleMultiPartRequest(HttpServletRequest request)
throws FileSizeLimitExceededException
{
if(!isMultipartRequest(request))
return null;
ServletFileUpload upload = FileUploader.getservletFileUploader(tempDir, 50);
MultiPartFormData data = new MultiPartFormData();
try
{
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items)
{
if(item.isFormField())
{
data.getParameters().put(item.getFieldName(), item.getString());
}
else
{
String filename = item.getName();
//Internet explorer and firefox will send the file name differently
//Internet explorer will send the entire path to the file name including
//the backslash characters etc ... we should strip it down
//THIS IS HACKY
if(filename.indexOf("\\") != -1)
{
int index = filename.lastIndexOf("\\");
filename = filename.substring(index + 1);
}
if(filename == null || filename.equals(""))
{
//do nothing
}
else
{
File uploadFile = new File(uploadDir + File.separator + randomFileName);
item.write(uploadFile);
data.addFile(item.getFieldname(), item.getString());
}
}
}
}
catch(FileSizeLimitExceededException e)
{
throw e;
}
catch(Exception e)
{
e.printStackTrace();
}
return data;
}
After parsing the request I am storing it in some object called MultipartFormData which can be used to get request parameters
public class MultiPartFormData {
private Hashtable<String, String> parameters;
private Hashtable<String, String> uploadedFiles;
public MultiPartFormData()
{
this.parameters = new Hashtable<String, String>();
this.uploadedFiles = new Hashtable<String, String>();
}
public Hashtable<String, String> getParameters() {
return parameters;
}
public void setParameters(Hashtable<String, String> parameters) {
this.parameters = parameters;
}
public void getParameter(String paramName) {
if(this.parameters.contains(paramName))
return tyhis.parameters.get(paramName);
return null;
}
public void addFile(String key, String filename) {
uploadedFile.put(key, filename);
}
public void getFilename(String key) {
uploadedFile.get(key);
}
}
I had a similar problem, and in that case the reason was: The IT department had set some settings on their firewall that stopped the execution of some of my scripts and only for some of the clients. The halt sent the browser to the root web page of my server. They were not able to explain in detail, but after opening up some filters, it all works as intended. WAMP, PHP7.
If it's a enctype="multipart/form-data" form you have to get the inputs with request.getPart("inputFileName").
For example for doc1 could be like:
Part doc1 = request.getPart("doc1");
Then you can do something like this:
//For name of the file:
String fileName = doc1.getSubmittedFileName();