I'm using Spring MVC 3 and I have the following Controller
#RequestMapping(value="FileUploadForm",method=RequestMethod.GET)
public String showForm(ModelMap model){
UploadForm form = new UploadForm();
model.addAttribute("FORM", form);
return "FileUploadForm";
}
#RequestMapping(value="FileUploadForm",method=RequestMethod.POST)
public ModelAndView processForm(#ModelAttribute(value="FORM") UploadForm form,BindingResult result){
if(!result.hasErrors()){
FileOutputStream outputStream = null;
String filePath = System.getProperty("java.io.tmpdir") + "/" + form.getFile().getOriginalFilename();
try {
outputStream = new FileOutputStream(new File(filePath));
outputStream.write(form.getFile().getFileItem().get());
outputStream.close();
System.out.println(form.getName());
return new ModelAndView(new RedirectView("success?Filepath="+filePath, true, true, false));
} catch (Exception e) {
System.out.println("Error while saving file");
return new ModelAndView("FileUploadForm");
}
}else{
return new ModelAndView("FileUploadForm");
}
}
This controller get the filepath and use to do a blast
#RequestMapping(value="success")
public String blasta(#ModelAttribute("Filepath") String filepath, Model model){
Blast sb = new Blast("somepath");
String[] blastIt = sb.blast("somepath", filepath);
String newLine = System.getProperty("line.separator");
ArrayList<Object> result = new ArrayList<>();
for (int i = 5; i < blastIt.length; i++) {
if(blastIt[i].startsWith("Lambda")){
break;
} else {
seila.add(blastIt[i]);
System.out.println(blastIt[i]);
}
model.addAttribute("RESULT", result);
}
File f1 = new File(filepath);
f1.delete();
return "success";
}
Everything works fine, but I still get the filepath in the url.
http://localhost:8081/Ambase/success?Filepath=filePath
And I want this way if it's possible
http://localhost:8081/Ambase/success
try adding this code to servlet-config.xml
<mvc:annotation-driven ignoreDefaultModelOnRedirect="true" />
To avoid this issue you should use RedirectAttributes. It will add the value of filePath to the redirect view params and you can get that in the controller blasta.
To achieve this you need to add one more parameter in the controller function processForm. At the end of all the parameters add RedirectAttributes attributes and then add following line just above the RedirectView statement.
attributes.addFlashAttribute("Filepath",filePath);
And then you can get this attribute in the ModelMap inside blasta controller function.
Hope this helps you. Cheers.
Related
I am learning Spring MVC online. As part of my course, I have to develop a Cloud Video Service. Specifications are mentioned here.
https://github.com/juleswhite/mobile-cloud-asgn1
Below is my controller class.
#Controller
public class VideosController {
private final AtomicLong currentId = new AtomicLong(1L);
//A Map to hold incoming Video meta data
private HashMap<Long, Video> videoMap = new HashMap<Long, Video>();
//Receives GET requests to /video and returns the current list
// list of videos in memory
#RequestMapping(value = "/video", method = RequestMethod.GET)
public #ResponseBody List<Video> getVideoList() throws IOException{
List<Video> resultList = new ArrayList<Video>();
for(Long id : videoMap.keySet()) {
resultList.add(videoMap.get(id));
}
return resultList;
}
//Receives POST requests to /video and adds the video object
//created from request data to the Map
#RequestMapping(value = "/video", method = RequestMethod.POST)
public #ResponseBody() Video addVideoMetadata(#RequestBody Video data)
{
//create a Video object
Video video = Video.create().withContentType(data.getContentType())
.withDuration(data.getDuration())
.withSubject(data.getSubject())
.withTitle(data.getTitle()).build();
//set the id for the video
long videoId = currentId.incrementAndGet();
video.setId(videoId);
//set the URL for this Video
String videoURL = getDataUrl(videoId);
video.setDataUrl(videoURL);
//save the Video metadata object to map
Video v = save(video);
return v;
}
// Receives POST requests to /video/{id}/data e.g. /videoa/2/data
// uploads the video file sent as MultipartFile
// and writes it to the disc
#RequestMapping(value = "/video/{id}/data", method = RequestMethod.POST)
public #ResponseBody ResponseEntity<VideoStatus> uploadVideo
(#RequestParam("data") MultipartFile data,
#PathVariable("id") long id,
HttpServletResponse response
) throws IOException
{
// if video with id not present
if(!videoMap.containsKey(id)) {
System.out.println(" this id not present");
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
//return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
InputStream in = null;
try {
//read the input stream
in = data.getInputStream();
}
catch(IOException ie){
System.out.println("Exception reading inputstream");
}
finally {
in.close();
}
//get the video
Video v = videoMap.get(id);
//write it to disk
VideoFileManager.get().saveVideoData(v, in);
VideoStatus vs = new VideoStatus(VideoStatus.VideoState.READY);
return new ResponseEntity<>(vs, HttpStatus.OK);
//response.setStatus(200);
//return new ResponseEntity<>(vs, HttpStatus.OK);
}
//Reads GET request to /vide/{id}/data and returns the video
//binary data as output stream
#RequestMapping(value = "/video/{id}/data", method = RequestMethod.GET)
public #ResponseBody ResponseEntity<OutputStream> getBinaryData(
#PathVariable("id") long videoId,
HttpServletResponse response) throws IOException {
//if id is incorrect
if(!videoMap.containsKey(videoId)) {
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
//get the video from Map
Video outVideo = videoMap.get(videoId);
VideoFileManager vm = VideoFileManager.get();
//write the binary data to OutputStream
OutputStream os = response.getOutputStream();
vm.copyVideoData(outVideo, os);
return new ResponseEntity<>(os, HttpStatus.OK);
}
//save incoming video metadata to a Map
public Video save(Video v) {
checkAndSetId(v);
if(!videoMap.containsKey(v.getId())) {
videoMap.put(v.getId(), v);
}
return v;
}
//helper method to generate url for video
private String getDataUrl(long videoId){
String url = getUrlBaseForLocalServer() + "/video/" + videoId + "/data";
return url;
}
private String getUrlBaseForLocalServer() {
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String base =
"http://"+request.getServerName()
+ ((request.getServerPort() != 80) ? ":"+request.getServerPort() : "");
return base;
}
private void checkAndSetId(Video entity) {
if(entity.getId() == 0){
entity.setId(currentId.incrementAndGet());
}
}
}
Now, I pass all the tests in AutoGradingTest.java Unit code but not the testAddVideoData(). It gives a Socket Time out error, followed by Infinite recursion error, pointing to line number 159 in the AutoGradingTest.java
Logically, my code seems to be fine. Lot of other learners are facing problem with thirstiest case too but there is no help from the course instructors.
Can somebody please help me here? Thanks a lot.
What I want to do:
Sending push notification to admin after an user do a specific thing.
Problem:
If I use RedirectAttributes, i need to return a string value for calling another endpoint but I need to return a http response and a model to user as well. So I wonder if there is another way to call another endpoint or what is the proper way to do that with RedirectAttributes.
#GetMapping("get_admin")
public ResponseEntity<Admin> getAdminById(#RequestHeader("lang") String locale,
#RequestParam("id") Integer id,
RedirectAttributes redirectAttrs) throws EntityNotFoundException {
Admin admin = adminService.getAdminById(id);
if (admin == null) {
return new ResponseEntity(new ResponseAdmin(new LangString().getNoSuchAnAdmin(locale),"0"), HttpStatus.OK);
}
redirectAttrs.addFlashAttribute("locale",locale);
redirectAttrs.addFlashAttribute("opType","0");
redirectAttrs.addFlashAttribute("message","message");
redirectAttrs.addFlashAttribute("type","type");
redirectAttrs.addFlashAttribute("data","data");
return new ResponseEntity(new ResponseAdmin(admin), HttpStatus.OK);
>>> I can't write "return redirect:/push_call;" since return type must be ResponseEntity, not String.
}
#GetMapping("push_call")
public ResponseEntity<String> redirectedPush(Model model){
int opType = (int) model.asMap().get("opType");;
String locale = (String) model.asMap().get("locale");;
String messageStr = (String) model.asMap().get("message");;
String dataStr = (String) model.asMap().get("data");;
String typeStr = (String) model.asMap().get("type");;
JSONObject body = new JSONObject();
body.put("to", "XXXXXX");
HttpEntity<String> request = new HttpEntity<>(body.toString());
CompletableFuture<String> pushNotification = androidPushNotificationsService.send(request);
try {
String firebaseResponse = pushNotification.get();
return new ResponseEntity<>(firebaseResponse, HttpStatus.OK);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return new ResponseEntity<>("Push Notification ERROR!", HttpStatus.BAD_REQUEST);
}
Just return redirectedPush(model) then
#Controller
#RequestMapping(value = "/admin/room")
public class Roomcontroller {
#Autowired
private RoomService roomService;
#RequestMapping(method = RequestMethod.GET)
public String index(ModelMap map) throws SQLException {
map.addAttribute("Room", roomService.getAll());
return "admin/room/index";
}
#RequestMapping(value = "/addroom", method = RequestMethod.GET)
public String addRoom() throws SQLException {
return "admin/room/addroom";
}
#RequestMapping(value = "/editroom/{ro_id}", method = RequestMethod.GET)
public ModelAndView edit(#PathVariable("ro_id") int ro_id) throws SQLException {
ModelAndView mv = new ModelAndView("admin/room/editroom");
mv.addObject("Room", roomService.getById(ro_id));
return mv;
}
#RequestMapping(value = "/deleteroom/{ro_id}", method = RequestMethod.GET)
public String delete(#PathVariable("ro_id") int ro_id) throws SQLException {
roomService.delete(ro_id);
return "redirect:/admin/room";
}
this portion of the code is used for saving image and other entities but I am not able to see the image stored in desired folder
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(#RequestParam("roomType") String roomType,
#RequestParam("roomDescription") String roomDescription, #RequestParam("roomNumber") int roomNumber,
#RequestParam("file") MultipartFile multipartFile, HttpServletRequest req) throws SQLException, IOException {
Room room = new Room();
room.setRoom_type(roomType);
room.setRoom_description(roomDescription);
room.setRoom_number(roomNumber);
// TO DO : Save room, fetch the id of saved room and set it through
// setter in above object.
if(room.getRo_id()==0){
String serverRootPath = req.getServletContext().getRealPath("");
System.out.println(serverRootPath);
// You can change the directory.
File roomImageDirectory = new File(serverRootPath + "D:\\Hotels\\ploadedImages");
if (!roomImageDirectory.exists()) {
roomImageDirectory.mkdirs();
}
String[] fileNameToken = multipartFile.getOriginalFilename().split("\\.");
// You can change file name to be saved.
String newFileName = "room-" + room.getRo_id() + "." + fileNameToken[fileNameToken.length - 1];
File roomImage = new File(roomImageDirectory, "/" + newFileName);
roomImage.createNewFile();
multipartFile.transferTo(roomImage);
room.setImage(newFileName);
roomService.insert(room);
}
else{
roomService.update(room);
}
return "redirect:/admin/room";
}
}
According to your code, you want to save your file under D:\\Hotels\\ploadedImages. So you don't need to use req.getServletContext().getRealPath(""). Just change your code like this
File roomImageDirectory = new File("D:\\Hotels\\ploadedImages");
...
File roomImage = new File(roomImageDirectory, "/" + newFileName);
I prefer File.separator instead of using / or \\
probably you are constructing a wrong path
try,
String pathToUpload = req.getServletContext().getRealPath("/fileuploads");
File f = new File(pathToUpload);
if(f.exists() && !f.isDirectory()) {
f.mkdir();
}
String orgName = multipartFile.getOriginalFilename();
String filePath = pathToUpload + orgName;
File dest = new File(pathToUpload);
file.transferTo(dest);
you should see file created inside root folder of your application context.
I've written a transformer class that takes an HttpServletRequest and transforms it into another type that holds a pointer to the InputStream from the servlet request. (The idea is to abstract the incoming transport protocol from the request handling, so I could also write a similar transformer from FTP, for instance.)
Now I'm trying to write a unit test for this, and I'm having problems. I've managed to figure out the correct boilerplate to create a valid Multipart HTTP request (using the Spring classes MockMultipartHttpServletRequest and MockMultipartFile), but now I get a NullPointerException in the initialize() method of my UploadRequest class. I'm guessing the problem is that somehow the stream inside the MockMultipartHttpServletRequest isn't being initialized correctly, but I can't figure out what I should do differently.
Any suggestions would be gratefully accepted!
This is the stack trace:
java.lang.NullPointerException
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:976)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:886)
at java.io.InputStream.read(InputStream.java:82)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:96)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:66)
at org.apache.commons.fileupload.MultipartStream.readBodyData(MultipartStream.java:592)
at org.apache.commons.fileupload.MultipartStream.discardBodyData(MultipartStream.java:618)
at org.apache.commons.fileupload.MultipartStream.skipPreamble(MultipartStream.java:637)
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:984)
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:965)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
at org.apache.commons.fileupload.servlet.ServletFileUpload.getItemIterator(ServletFileUpload.java:148)
at com.ooyala.UploadRequest.initialize(UploadRequest.java:51)
at com.ooyala.UploadRequestTest.testCreateFromServletRequest(UploadRequestTest.java:57)
Here's an abbreviated version of my transformer class:
public class UploadRequest {
private Map<String, String> params;
private InputStream strIn;
private Logger Log = Logger.getLogger(UploadRequest.class.getName());
public UploadRequest()
{
params = new HashMap<String, String>();
}
public void initialize(HttpServletRequest sRequest,
ServletFileUpload upload)
throws IOException, FileUploadException
{
Enumeration<String> paramNames = sRequest.getParameterNames();
while (paramNames.hasMoreElements()) {
String pName = paramNames.nextElement();
params.put(pName, sRequest.getParameter(pName));
}
params.put("request_uri", sRequest.getRequestURI());
FileItemIterator iter = upload.getItemIterator(sRequest);
while (iter.hasNext()) {
FileItemStream item = iter.next();
try {
if (!item.isFormField()) {
// Skip form fields
params.put("original_file_name", item.getName());
strIn = item.openStream();
}
} catch (IOException ex) {
Log.severe("File uploading exception: " + ex.getMessage());
throw ex;
}
}
}
And here's the unit test:
import org.springframework.mock.web.MockMultipartHttpServletRequest;
import org.springframework.mock.web.MockMultipartFile;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
// etc.... other imports
#RunWith(JMock.class)
public class UploadRequestTest {
private UploadRequest upRequest;
#Before
public void setUp()
{
context.setImposteriser(ClassImposteriser.INSTANCE);
upRequest = new UploadRequest();
}
#Test
public void testCreateFromServletRequest()
throws IOException, FileUploadException
{
String text_contents = "hello world";
MockMultipartHttpServletRequest sRequest =
new MockMultipartHttpServletRequest();
sRequest.setMethod("POST");
String boundary = generateBoundary();
String contentType = "multipart/form-data; boundary="+boundary;
sRequest.setContentType(contentType);
sRequest.setRequestURI("/foo");
sRequest.addParameter("test_param","test_value");
sRequest.addFile(
new MockMultipartFile("file1","test_upload.txt","text/plain",
text_contents.getBytes()));
ServletFileUpload upload = new ServletFileUpload();
assertTrue(upload.isMultipartContent(sRequest));
upRequest.initialize(sRequest, upload);
}
}
I have the same issue and I googled but no answer. I plugged in the source code from the library, You need to send content, whatever. The library might need to check if it is null in the skip method
MockMultipartHttpServletRequest request
request.setContent("whatever".getBytes());
Posted here for others
Add boundary condition
Generate contents as follows
MockMultipartHttpServletRequest request =
this.generateMockMultiPartHttpServletRequest(true);
MockMultipartFile mockMultipartFile = null;
try {
request.setContentType("multipart/form-data; boundary=-----1234");
request.setCharacterEncoding("text/plain");
String endline = "\r\n";
String bondary = "-----1234";
String textFile = this.encodeTextFile("-----1234", "\r\n", "file","test.csv",
"text/UTF-8", FileUtils.readFileToString((new File(csvFilePath)), "UTF-8"));
StringBuilder content = new StringBuilder(textFile.toString());
content.append(endline);
content.append(endline);
content.append(endline);
content.append("--");
content.append(bondary);
content.append("--");
content.append(endline);
request.setContent(content.toString().getBytes());
request.setMethod("POST");
mockMultipartFile = new MockMultipartFile("file",
FileUtils.readFileToByteArray(new File(csvFilePath)));
} catch (Exception e1) {
e1.printStackTrace();
}
request.addFile(mockMultipartFile);
Function to encode text
private String encodeTextFile(String bondary, String endline, String name,
String filename, String contentType, String content) {
final StringBuilder sb = new StringBuilder(64);
sb.append(endline);
sb.append("--");
sb.append(bondary);
sb.append(endline);
sb.append("Content-Disposition: form-data; name=\"");
sb.append(name);
sb.append("\"; filename=\"");
sb.append(filename);
sb.append("\"");
sb.append(endline);
sb.append("Content-Type: ");
sb.append(contentType);
sb.append(endline);
sb.append(endline);
sb.append(content);
return sb.toString();
}
I went through the same problem, after searching lot I got this post in which I answered with code that solved my problem.
The Shriprasad's solution works well for text file. But I had some problems with binary files.
https://stackoverflow.com/a/30541653/2762092
I have got this piece of code (I didn't write, just maintaining):
public class MyMultipartResolver extends CommonsMultipartResolver{
public List parseEmptyRequest(HttpServletRequest request) throws IOException, FileUploadException {
String contentType = request.getHeader(CONTENT_TYPE);
int boundaryIndex = contentType.indexOf("boundary=");
InputStream input = request.getInputStream();
byte[] boundary = contentType.substring(boundaryIndex + 9).getBytes();
MultipartStream multi = new MultipartStream(input, boundary);
multi.setHeaderEncoding(getHeaderEncoding());
ArrayList items = new ArrayList();
boolean nextPart = multi.skipPreamble();
while (nextPart) {
Map headers = parseHeaders(multi.readHeaders());
// String fieldName = getFieldName(headers);
String subContentType = getHeader(headers, CONTENT_TYPE);
if (subContentType == null) {
FileItem item = createItem(headers, true);
OutputStream os = item.getOutputStream();
try {
multi.readBodyData(os);
} finally {
os.close();
}
items.add(item);
} else {
multi.discardBodyData();
}
nextPart = multi.readBoundary();
}
return items;
}
}
I am using commons-fileupload.jar version 1.2.1 and obviously the code is using some deprecated methods...
Anyway, while trying to use this code to upload a very large file (780 MB) I get this:
org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:983)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:887)
at java.io.InputStream.read(InputStream.java:89)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:94)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:64)
at org.apache.commons.fileupload.MultipartStream.readBodyData(MultipartStream.java:593)
at org.apache.commons.fileupload.MultipartStream.discardBodyData(MultipartStream.java:619)
that is thrown from 'multi.discardBodyData();' line.
My question:
How can I avoid this error and be able to be able to succeed collecting the FileItems?
catch
(org.apache.commons.fileupload.MultipartStream.MalformedStreamException e)
{
e.printStackTrace();
return ERROR;
}
Catch the exception and handle it via ..either InputStream or Return Error use it in struts action tag