Skip to content

Commit 74d7320

Browse files
committed
add video list, get and upload apis
1 parent cfcfc1a commit 74d7320

10 files changed

+213
-12
lines changed

src/main/java/com/streaming/Application.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package com.streaming;
22

3+
import com.streaming.services.FileStorageProperties;
34
import org.springframework.boot.SpringApplication;
45
import org.springframework.boot.autoconfigure.SpringBootApplication;
6+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
57
import org.springframework.context.annotation.Bean;
68
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
79

810
@SpringBootApplication
11+
@EnableConfigurationProperties({
12+
FileStorageProperties.class
13+
})
914
public class Application {
1015

1116
@Bean

src/main/java/com/streaming/controllers/UserController.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
import com.streaming.repositories.UserRepository;
55
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
66
import org.springframework.web.bind.annotation.PostMapping;
7+
import org.springframework.web.bind.annotation.RequestBody;
78
import org.springframework.web.bind.annotation.RequestMapping;
89
import org.springframework.web.bind.annotation.RestController;
910

11+
import java.util.Date;
12+
1013
@RestController
1114
@RequestMapping("/users")
1215
public class UserController {
@@ -21,8 +24,10 @@ public UserController(UserRepository userRepository,
2124
}
2225

2326
@PostMapping("/sign-up")
24-
public void signUp(String username, String password) {
25-
User user = new User(username, bCryptPasswordEncoder.encode(password));
27+
public void signUp(@RequestBody User user) {
28+
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
29+
user.setCreated(new Date());
30+
user.setModified(new Date());
2631
userRepository.save(user);
2732
}
2833
}
Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,93 @@
11
package com.streaming.controllers;
22

3+
import com.streaming.domains.User;
34
import com.streaming.domains.Video;
5+
import com.streaming.repositories.UserRepository;
46
import com.streaming.repositories.VideoRepository;
5-
import org.springframework.web.bind.annotation.PostMapping;
6-
import org.springframework.web.bind.annotation.RequestMapping;
7-
import org.springframework.web.bind.annotation.RestController;
7+
import com.streaming.services.FileStorageService;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
import org.springframework.core.io.Resource;
11+
import org.springframework.http.HttpHeaders;
12+
import org.springframework.http.MediaType;
13+
import org.springframework.http.ResponseEntity;
14+
import org.springframework.security.core.context.SecurityContextHolder;
15+
import org.springframework.web.bind.annotation.*;
16+
import org.springframework.web.multipart.MultipartFile;
817

18+
import javax.servlet.http.HttpServletRequest;
19+
import java.io.IOException;
920
import java.util.ArrayList;
21+
import java.util.Arrays;
1022
import java.util.List;
23+
import java.util.Optional;
1124

1225
@RestController
1326
@RequestMapping("/videos")
1427
public class VideoController {
1528

29+
private static final Logger logger = LoggerFactory.getLogger(VideoController.class);
30+
1631
private VideoRepository videoRepository;
32+
private UserRepository userRepository;
33+
private FileStorageService fileStorageService;
1734

18-
public VideoController(VideoRepository videoRepository) {
35+
public VideoController(VideoRepository videoRepository,
36+
UserRepository userRepository,
37+
FileStorageService fileStorageService) {
1938
this.videoRepository = videoRepository;
39+
this.userRepository = userRepository;
40+
this.fileStorageService = fileStorageService;
2041
}
2142

22-
@PostMapping("/list")
43+
@GetMapping("/list")
2344
public List<Video> listVideos() {
24-
List<Video> list = new ArrayList<>();
25-
videoRepository.findAll().forEach(list::add);
26-
return list;
45+
return videoRepository.findByUserUsername(SecurityContextHolder.getContext().getAuthentication().getName());
46+
}
47+
48+
@PostMapping("/upload")
49+
public Video uploadVideo(@RequestParam("file") MultipartFile file, String title) {
50+
//store video file on the server
51+
String fileName = fileStorageService.storeFile(file);
52+
53+
//load user details
54+
User user = userRepository.findByUsername(SecurityContextHolder.getContext().getAuthentication().getName());
55+
56+
//create a new video object
57+
Video video = new Video(user, title, file.getSize(), fileName);
58+
videoRepository.save(video);
59+
60+
//return video object
61+
return video;
62+
}
63+
64+
@GetMapping("/get/{id:.+}")
65+
public Video getVideo(@PathVariable Long id) {
66+
Optional<Video> video = videoRepository.findById(id);
67+
return video.isPresent() ? video.get() : null;
68+
}
69+
70+
@GetMapping("/download/{fileName:.+}")
71+
public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request) {
72+
// Load file as Resource
73+
Resource resource = fileStorageService.loadFileAsResource(fileName);
74+
75+
// try to find file's content type
76+
String contentType = null;
77+
try {
78+
contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
79+
} catch (IOException ex) {
80+
logger.info("Could not determine file type.");
81+
}
82+
83+
// fallback content type
84+
if (contentType == null) {
85+
contentType = "application/octet-stream";
86+
}
87+
88+
return ResponseEntity.ok()
89+
.contentType(MediaType.parseMediaType(contentType))
90+
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
91+
.body(resource);
2792
}
2893
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.streaming.exceptions;
2+
3+
public class FileStorageException extends RuntimeException {
4+
public FileStorageException(String message) {
5+
super(message);
6+
}
7+
8+
public FileStorageException(String message, Throwable cause) {
9+
super(message, cause);
10+
}
11+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.streaming.exceptions;
2+
3+
import org.springframework.http.HttpStatus;
4+
import org.springframework.web.bind.annotation.ResponseStatus;
5+
6+
@ResponseStatus(HttpStatus.NOT_FOUND)
7+
public class MyFileNotFoundException extends RuntimeException {
8+
public MyFileNotFoundException(String message) {
9+
super(message);
10+
}
11+
12+
public MyFileNotFoundException(String message, Throwable cause) {
13+
super(message, cause);
14+
}
15+
}

src/main/java/com/streaming/repositories/VideoRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@
33
import com.streaming.domains.Video;
44
import org.springframework.data.repository.PagingAndSortingRepository;
55

6+
import java.util.List;
7+
68
public interface VideoRepository extends PagingAndSortingRepository<Video, Long> {
9+
List<Video> findByUserUsername(String user);
710
}

src/main/java/com/streaming/security/JWTAuthenticationFilter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
import com.auth0.jwt.JWT;
44
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.streaming.domains.User;
56
import org.springframework.security.authentication.AuthenticationManager;
67
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
78
import org.springframework.security.core.Authentication;
89
import org.springframework.security.core.AuthenticationException;
9-
import org.springframework.security.core.userdetails.User;
1010
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
1111

1212
import javax.servlet.FilterChain;
@@ -52,7 +52,7 @@ protected void successfulAuthentication(HttpServletRequest req,
5252
Authentication auth) throws IOException, ServletException {
5353

5454
String token = JWT.create()
55-
.withSubject(((User) auth.getPrincipal()).getUsername())
55+
.withSubject(((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername())
5656
.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
5757
.sign(HMAC512(SECRET.getBytes()));
5858
res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.streaming.services;
2+
3+
import org.springframework.boot.context.properties.ConfigurationProperties;
4+
5+
@ConfigurationProperties(prefix = "file")
6+
public class FileStorageProperties {
7+
private String uploadDir;
8+
9+
public String getUploadDir() {
10+
return uploadDir;
11+
}
12+
13+
public void setUploadDir(String uploadDir) {
14+
this.uploadDir = uploadDir;
15+
}
16+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.streaming.services;
2+
3+
import com.streaming.exceptions.FileStorageException;
4+
import com.streaming.exceptions.MyFileNotFoundException;
5+
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.core.io.Resource;
7+
import org.springframework.core.io.UrlResource;
8+
import org.springframework.stereotype.Service;
9+
import org.springframework.util.StringUtils;
10+
import org.springframework.web.multipart.MultipartFile;
11+
12+
import java.io.IOException;
13+
import java.net.MalformedURLException;
14+
import java.nio.file.Files;
15+
import java.nio.file.Path;
16+
import java.nio.file.Paths;
17+
import java.nio.file.StandardCopyOption;
18+
19+
@Service
20+
public class FileStorageService {
21+
22+
private final Path fileStorageLocation;
23+
24+
@Autowired
25+
public FileStorageService(FileStorageProperties fileStorageProperties) {
26+
this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
27+
.toAbsolutePath().normalize();
28+
29+
try {
30+
Files.createDirectories(this.fileStorageLocation);
31+
} catch (Exception ex) {
32+
throw new FileStorageException("Could not create the directory where the uploaded files will be stored.", ex);
33+
}
34+
}
35+
36+
public String storeFile(MultipartFile file) {
37+
// Normalize file name
38+
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
39+
40+
try {
41+
// Check if the file's name contains invalid characters
42+
if (fileName.contains("..")) {
43+
throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName);
44+
}
45+
46+
// Copy file to the target location (Replacing existing file with the same name)
47+
Path targetLocation = this.fileStorageLocation.resolve(fileName);
48+
Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
49+
50+
return fileName;
51+
} catch (IOException ex) {
52+
throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex);
53+
}
54+
}
55+
56+
public Resource loadFileAsResource(String fileName) {
57+
try {
58+
Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
59+
Resource resource = new UrlResource(filePath.toUri());
60+
if (resource.exists()) {
61+
return resource;
62+
} else {
63+
throw new MyFileNotFoundException("File not found " + fileName);
64+
}
65+
} catch (MalformedURLException ex) {
66+
throw new MyFileNotFoundException("File not found " + fileName, ex);
67+
}
68+
}
69+
}

src/main/resources/application.properties

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,15 @@ spring.datasource.url=jdbc:mysql://localhost/live-streaming?useUnicode=true&char
33
spring.datasource.username=root
44
spring.datasource.password=
55
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
6+
7+
## MULTIPART (MultipartProperties)
8+
# Enable multipart uploads
9+
spring.servlet.multipart.enabled=true
10+
# Threshold after which files are written to disk.
11+
spring.servlet.multipart.file-size-threshold=2KB
12+
# Max file size.
13+
spring.servlet.multipart.max-file-size=200MB
14+
# Max Request Size
15+
spring.servlet.multipart.max-request-size=215MB
16+
## File Storage Properties
17+
file.upload-dir=./uploads

0 commit comments

Comments
 (0)