I need to create a REST api that saves the names in a .txt file and that I can retrieve them when I needed. Below I have the code. I'm using the spring boot framework.
My REST controller:
#RequestMapping(value = "/people", method = RequestMethod.POST)
public #ResponseBody ResponseEntity<String> escreverArquivo() throws Exception {
String line = "";
try {
File file = new File("nomes.txt");
// Se o arquivo nao existir, ele gera
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile(), true);
BufferedWriter bw = new BufferedWriter(fw);
// Escreve e fecha arquivo
bw.write(line);
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
return new ResponseEntity<String>(line, HttpStatus.CREATED);
}
#RequestMapping(value = "/pessoas", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> lerArquivo() throws Exception {
String line = null;
try {
FileReader ler = new FileReader("nomes.txt");
BufferedReader reader = new BufferedReader(ler);
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return new ResponseEntity<String>(line, HttpStatus.OK);
}
The first method does not add anything that is not within the string line, the second method does not show anything on the screen, only in the sts console.
You should not be using a text file for storing any data you want to keep for any amount of time. They are not a reliable way of storing data, particularly as the load on your api increases.
You mention in a comment that your test requires a text file, but you should consider whether this is a good idea or not. Your tests should test the behaviour of your code, not the implementation. The tests should be happy with any code that makes saveName() and getNames() (or equivalent functions) behave as expected.
It is really worth getting comfortable with the basics of Java first before trying to use something like Spring Boot.
However, if you are really desperate to save a string to a text file, the Apache Commons IO library provides several nice helper methods, most notably:
FileUtils.write(new File("myFile.txt"), "Content Text", "UTF-8");
However, I strongly urge you to consider whether you really want a text file that is unencrypted, non-reduntant, easily corruptible, and likely not backed-up to store important data.
You should capture the POST data and initialize the line String with it. Something like
#RequestMapping(value = "/people", method = RequestMethod.POST)
#ResponseBody
public String escreverArquivo(#RequestParam(value="nomeDaPessoa") String nomeDaPessoa) throws Exception {
String line = nomeDaPessoa;
// ...
}
Note that you should replace nomeDaPessoa with the name of the field coming from your Form.
Related
I am trying to write some unit tests to see if a logging method gets called for csv exceptions. The flow goes something like this:
CsvToBean is used to parse some info and each bean that is produced has some work done on it.
After all this, CsvToBean.getCapturedExceptions().forEach() is used to processed the exceptions.
How to I create some of these exceptions for testing?
public void parseAndSaveReportToDB(Reader reader, String reportFileName,ItemizedActivityRepository iaRepo,
ICFailedRecordsRepository icFailedRepo,
String reportCols) throws Exception {
try {
CsvToBean<ItemizedActivity> csvToBean = new CsvToBeanBuilder<ItemizedActivity>(reader).withType(ItemizedActivity.class).withThrowExceptions(false).build();
csvToBean.parse().forEach(itmzActvty -> {
itmzActvty.setReportFileName(reportFileName);
String liteDesc = itmzActvty.getBalanceTransactionDescription();
if (liteDesc.contains(":")) {
liteDesc = liteDesc.substring(liteDesc.indexOf(":")+1).trim();
}
itmzActvty.setLiteDescription(liteDesc);
itmzActvty.setAmount(convertCentToDollar(itmzActvty.getAmount()));
iaRepo.save(itmzActvty);
});
log.info("Successfully saved report data in DB");
csvToBean.getCapturedExceptions().forEach(csvExceptionObj -> logFailedRecords(reportFileName, csvExceptionObj, icFailedRepo, reportCols));
reader.close();
} catch (Exception ex) {
log.error("Exception when saving report data to DB", ex);
throw ex;
}
}
In this code I need to trigger the logFailedRecords method. To do so I need to fill the captured exceptions queue with an exception. I don't know how to get an exception in there.
What I have is not much since I keep hitting walls
#Test
public void testParseAndSaveReportToDBWithExceptions() throws Exception {
// CsvException csvExceptionObject = new CsvException("testException");
CsvToBean<ItemizedActivity> csvToBean = mock(CsvToBean.class);//<ItemizedActivity>(reader).withType(ItemizedActivity.class).withThrowExceptions(false).build().class);
BufferedReader reader = mock(BufferedReader.class);
ReportingMetadata rmd = this.getReportingMetadata();
verify(this.reportsUtil).parseAndSaveReportToDB(reader,"test.csv",
this.iaRepo,this.icFailedRepo,rmd.getReportCols());
// System.out.println(csvToBean.getCapturedExceptions().toString());
}
I want to save data with jackson to existing file (update it) but it won't work when I run my project from jar.
I need to use json as "database" (I know it's pretty stupid but that's for a school project) and to do it I load and save all the data when I do any of CRUD operations. It's working fine when I run it with IDE but when I tried as a jar it had a problem with reading file from ClassPathResource.
So I have this method to save changes to file:
private List<Item> items;
private ObjectMapper mapper;
private ObjectWriter writer;
public void saveData() {
mapper = new ObjectMapper();
writer = mapper.writer(new DefaultPrettyPrinter());
try {
writer.writeValue(new ClassPathResource("items.json").getFile(), items);
} catch (IOException e) {
e.printStackTrace();
}
}
And it works just fine when i run this through IntelliJ but it won't work when I run it as a jar.
I found a solution to loading the data by using InputStream from this question and method looks like this:
public void loadData() {
mapper = new ObjectMapper();
try {
ClassPathResource classPathResource = new ClassPathResource("items.json");
InputStream inputStream = classPathResource.getInputStream();
File tempFile = File.createTempFile("test", ".json");
FileUtils.copyInputStreamToFile(inputStream, tempFile);
System.out.println(tempFile);
System.out.println(ItemDao.class.getProtectionDomain().getCodeSource().getLocation().getPath().toString());
items = mapper.readValue(tempFile, new TypeReference<List<Item>>() {
});
} catch (IOException e) {
items = null;
e.printStackTrace();
}
}
But I still have no idea how to actually save changes. I was thinking about making use of FileOutputStreambut I achieved nothing.
So I want to get this working in jar file and be able to save changes to the same file, thanks for help in advance!
when you want to do read/write operations, it is better keep the file outside of the project. when running the jar, pass file name with path as an argument. like -DfileName=/Users/chappa/Documents/items.json etc. This way, you have absolute path, and you can perform read/write operations on it
if you are using java 1.7 or above, use below approach to write data.
To read data, you can use jackson api to load the json file as is.
Path wipPath = Paths.get("/Users/chappa/Documents/items.json");
try (BufferedWriter writer = Files.newBufferedWriter(wipPath)) {
for (String record : nosRecords) {
writer.write(record);
}
}
Just in case if you want to read json using IO streams, you can use below code
Path wipPath = Paths.get("/Users/chappa/Documents/items.json");
try (BufferedReader reader = Files.newBufferedReader(wipPath)) {
String line=null;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
}
I'm creating a feature file programmatically using the following java code.
// This method will be invoked by 'constructFeatureFile()'
public static void createFeatureFile(String strFeatureFilePath, String strFeatureFileContent, String runnableFile)
{
try
{
if (strFeatureFilePath.trim().length() > 0 && strFeatureFileContent.trim().length() > 0)
{
// First time file creation
if (!Files.exists(Paths.get(strFeatureFilePath)))
{
FileWriter fw = new FileWriter(new File(strFeatureFilePath));
Writer wr = new BufferedWriter(fw);
wr.write(strFeatureFileContent);
wr.close();
} //If the exists, delete that file and create with fresh data
else if(Files.exists(Paths.get(strFeatureFilePath)))
{
Files.delete(Paths.get(strFeatureFilePath));
FileWriter fw = new FileWriter(new File(strFeatureFilePath));
Writer wr = new BufferedWriter(fw);
wr.write(strFeatureFileContent);
wr.close();
}
// Call Runner to run feature file
runner(runnableFile);
}
}
catch(Exception e)
{
System.out.print(e);
}
}
// Invoke feature file to execute
public static void runner(String runnableFile)
{
Map<String, Object> args = new HashMap<String,Object>();
args.put("name", "API Testing");
Map<String, Object> getResponse = CucumberRunner.runClasspathFeature(runnableFile, args, true);
getResponse = null;
}
The problem is, after creating the feature file, I'm calling Runner() method to execute the feature file. Its throwing the following exception.
java.lang.RuntimeException: file not found: country//getMembersDetails.feature
But, after refresing the folder (where the feature file was created), and re-run the same script, it's executing perfectly with the same feature file.
I don't understand why this is happening, what is the mistake I did here, anyone please provide suggestions.
Thanks!
It looks like createFeatureFile() is busy writing to strFeatureFilePath, but then calling runner(runnableFile). nothing was written to runnableFile?
I have a file with name foo.txt. This file contains some text. I want to achieve following functionality:
I launch program
write something to the file (for example add one row: new string in foo.txt)
I want to get ONLY NEW content of this file.
Can you clarify the best solution of this problem? Also I want resolve related issues: in case if I modify foo.txt I want to see diff.
The closest tool which I found in Java is WatchService but if I understood right this tool can only detect type of event happened on filesystem (create file or delete or modify).
Java Diff Utils is designed for that purpose.
final List<String> originalFileContents = new ArrayList<String>();
final String filePath = "C:/Users/BackSlash/Desktop/asd.txt";
FileListener fileListener = new FileListener() {
#Override
public void fileDeleted(FileChangeEvent paramFileChangeEvent)
throws Exception {
// use this to handle file deletion event
}
#Override
public void fileCreated(FileChangeEvent paramFileChangeEvent)
throws Exception {
// use this to handle file creation event
}
#Override
public void fileChanged(FileChangeEvent paramFileChangeEvent)
throws Exception {
System.out.println("File Changed");
//get new contents
List<String> newFileContents = new ArrayList<String> ();
getFileContents(filePath, newFileContents);
//get the diff between the two files
Patch patch = DiffUtils.diff(originalFileContents, newFileContents);
//get single changes in a list
List<Delta> deltas = patch.getDeltas();
//print the changes
for (Delta delta : deltas) {
System.out.println(delta);
}
}
};
DefaultFileMonitor monitor = new DefaultFileMonitor(fileListener);
try {
FileObject fileObject = VFS.getManager().resolveFile(filePath);
getFileContents(filePath, originalFileContents);
monitor.addFile(fileObject);
monitor.start();
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (FileNotFoundException e) {
//handle
e.printStackTrace();
} catch (IOException e) {
//handle
e.printStackTrace();
}
Where getFileContents is :
void getFileContents(String path, List<String> contents) throws FileNotFoundException, IOException {
contents.clear();
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));
String line = null;
while ((line = reader.readLine()) != null) {
contents.add(line);
}
}
What I did:
I loaded the original file contents in a List<String>.
I used Apache Commons VFS to listen for file changes, using FileMonitor. You may ask, why? Because WatchService is only available starting from Java 7, while FileMonitor works with at least Java 5 (personal preference, if you prefer WatchService you can use it). note: Apache Commons VFS depends on Apache Commons Logging, you'll have to add both to your build path in order to make it work.
I created a FileListener, then I implemented the fileChanged method.
That method load new contents form the file, and uses Patch.diff to retrieve all differences, then prints them
I created a DefaultFileMonitor, which basically listens for changes to a file, and I added my file to it.
I started the monitor.
After the monitor is started, it will begin listening for file changes.
I'm writing a play 2.0 java application that allows users to upload files. Those files are stored on a third-party service I access using a Java library, the method I use in this API has the following signature:
void store(InputStream stream, String path, String contentType)
I've managed to make uploads working using the following simple controller:
public static Result uploadFile(String path) {
MultipartFormData body = request().body().asMultipartFormData();
FilePart filePart = body.getFile("files[]");
InputStream is = new FileInputStream(filePart.getFile())
myApi.store(is,path,filePart.getContentType());
return ok();
}
My concern is that this solution is not efficient because by default the play framework stores all the data uploaded by the client in a temporary file on the server then calls my uploadFile() method in the controller.
In a traditional servlet application I would have written a servlet behaving this way:
myApi.store(request.getInputStream(), ...)
I have been searching everywhere and didn't find any solution. The closest example I found is Why makes calling error or done in a BodyParser's Iteratee the request hang in Play Framework 2.0? but I didn't found how to modify it to fit my needs.
Is there a way in play2 to achieve this behavior, i.e. having the data uploaded by the client to go "through" the web-application directly to another system ?
Thanks.
I've been able to stream data to my third-party API using the following Scala controller code:
def uploadFile() =
Action( parse.multipartFormData(myPartHandler) )
{
request => Ok("Done")
}
def myPartHandler: BodyParsers.parse.Multipart.PartHandler[MultipartFormData.FilePart[Result]] = {
parse.Multipart.handleFilePart {
case parse.Multipart.FileInfo(partName, filename, contentType) =>
//Still dirty: the path of the file is in the partName...
String path = partName;
//Set up the PipedOutputStream here, give the input stream to a worker thread
val pos:PipedOutputStream = new PipedOutputStream();
val pis:PipedInputStream = new PipedInputStream(pos);
val worker:UploadFileWorker = new UploadFileWorker(path,pis);
worker.contentType = contentType.get;
worker.start();
//Read content to the POS
Iteratee.fold[Array[Byte], PipedOutputStream](pos) { (os, data) =>
os.write(data)
os
}.mapDone { os =>
os.close()
Ok("upload done")
}
}
}
The UploadFileWorker is a really simple Java class that contains the call to the thrid-party API.
public class UploadFileWorker extends Thread {
String path;
PipedInputStream pis;
public String contentType = "";
public UploadFileWorker(String path, PipedInputStream pis) {
super();
this.path = path;
this.pis = pis;
}
public void run() {
try {
myApi.store(pis, path, contentType);
pis.close();
} catch (Exception ex) {
ex.printStackTrace();
try {pis.close();} catch (Exception ex2) {}
}
}
}
It's not completely perfect because I would have preferred to recover the path as a parameter to the Action but I haven't been able to do so. I thus have added a piece of javascript that updates the name of the input field (and thus the partName) and it does the trick.