Skip to content
Snippets Groups Projects
Commit 4285672e authored by Zhicheng Xu's avatar Zhicheng Xu
Browse files

update new function,upload images

parent 6ea3ee25
No related branches found
No related tags found
1 merge request!53Resolve "As a user, I want to have a page to upload and share photos so that another user can see my stories."
Showing
with 368 additions and 5 deletions
package uk.ac.cf.spring.demo.sports.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/uploads/**")
.addResourceLocations("file:./uploads/"); // 指定静态资源的实际路径
}
}
package uk.ac.cf.spring.demo.sports.images;
import java.io.IOException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/api/images")
public class ImageController {
private final ImageService imageService;
@Autowired
public ImageController(ImageService imageService) {
this.imageService = imageService;
}
@GetMapping
public List<Image> getImages() {
List<Image> images = imageService.getAllImages();
System.out.println("Returned JSON data: " + images);
return imageService.getAllImages();
}
@PostMapping
public ResponseEntity<Void> uploadImage(@RequestParam("image") MultipartFile file) {
try {
imageService.saveImage(file);
List<Image> images = imageService.getAllImages();
System.out.println("Returned JSON data: " + images);
return ResponseEntity.ok().build();
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
package uk.ac.cf.spring.demo.sports.images;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@Repository
public class ImageRepository {
private final JdbcTemplate jdbcTemplate;
@Autowired
public ImageRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public int save(String url) {
String sql = "INSERT INTO images (url) VALUES (?)";
return jdbcTemplate.update(sql, url);
}
// 获取所有图片记录
public List<Image> findAll() {
String sql = "SELECT * FROM images";
return jdbcTemplate.query(sql, new ImageRowMapper());
}
//映射方法
private static class ImageRowMapper implements RowMapper<Image> {
@Override
public Image mapRow(ResultSet rs, int rowNum) throws SQLException {
Image image = new Image();
image.setId(rs.getInt("id"));
image.setUrl(rs.getString("url"));
image.setUploadedAt(rs.getTimestamp("uploaded_at"));
return image;
}
}
}
package uk.ac.cf.spring.demo.sports.images;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
public interface ImageService {
List<Image> getAllImages();
void saveImage(MultipartFile file) throws IOException;
}
package uk.ac.cf.spring.demo.sports.images;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.beans.factory.annotation.Value;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
@Service
public class ImageServiceImpl implements ImageService {
private final ImageRepository imageRepository;
@Value("${image.upload.dir}")
private String uploadDir;
@Autowired
public ImageServiceImpl(ImageRepository imageRepository) {
this.imageRepository = imageRepository;
}
@Override
public List<Image> getAllImages() {
return imageRepository.findAll();
}
@Override
public void saveImage(MultipartFile file) throws IOException {
// 生成唯一文件名
String fileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
Path filePath = Paths.get(uploadDir, fileName);
// 确保目录存在
Files.createDirectories(filePath.getParent());
// 将文件写入目标目录
Files.write(filePath, file.getBytes());
// 保存图片路径到数据库
String url = "/uploads/" + fileName;
imageRepository.save(url);
}
}
......@@ -31,6 +31,8 @@ public class SecurityConfig {
"/html/login.html" , // login
"/rankings", //ranking data path
"/rankings/**",
"/uploads", //images
"/uploads/**",
};
......
......@@ -9,4 +9,5 @@ spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
#spring.mvc.view.suffix=.html # ????
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
\ No newline at end of file
spring.thymeleaf.mode=HTML
image.upload.dir=./uploads
\ No newline at end of file
......@@ -40,7 +40,6 @@ CREATE TABLE IF NOT EXISTS ranking (
);
CREATE TABLE images (
id INT AUTO_INCREMENT PRIMARY KEY,
filename VARCHAR(255) NOT NULL, -- 图片文件名或路径
uploader VARCHAR(100) NOT NULL, -- 上传者名称
upload_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 上传时间
url VARCHAR(255) NOT NULL, -- 图片文件名或路径
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP-- 上传时间
);
/* General Styles for Gallery */
.gallery-container {
max-width: 1200px;
margin: 20px auto;
padding: 20px;
text-align: center;
font-family: Arial, sans-serif;
background-color: #f9f9f9;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.gallery-container h1 {
margin-bottom: 20px;
font-size: 2em;
color: #333;
}
/* Carousel Styles */
.carousel {
position: relative;
overflow: hidden;
width: 80%;
margin: 0 auto;
max-height: 400px;
}
#carousel-images {
display: flex;
transition: transform 0.5s ease-in-out;
}
#carousel-images img {
max-width: 100%;
max-height: 400px;
object-fit: cover;
border-radius: 8px;
}
.carousel-button {
position: absolute;
top: 50%;
transform: translateY(-50%);
background-color: rgba(0, 0, 0, 0.5);
color: white;
border: none;
padding: 10px;
cursor: pointer;
border-radius: 50%;
font-size: 1.5em;
}
.carousel-button.prev {
left: 10px;
}
.carousel-button.next {
right: 10px;
}
.carousel-button:hover {
background-color: rgba(0, 0, 0, 0.8);
}
/* Upload Section */
.upload-section {
margin-top: 20px;
}
.upload-btn {
background-color: #007bff;
color: white;
border: none;
padding: 10px 20px;
font-size: 1em;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.upload-btn:hover {
background-color: #0056b3;
}
.carousel img {
display: block; /* Ensure the image displays as a block-level element */
margin: 0 auto; /* Horizontally centers the image */
max-width: 100%; /* Keep image responsive */
height: auto;
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>image gallery</title>
<link rel="stylesheet" href="/css/navBar.css">
<link rel="stylesheet" href="/css/footer.css">
<link rel="stylesheet" href="/css/gallery.css">
</head>
<body>
<div id="navbar-container"></div>
<!-- Main Content -->
<main class="gallery-container">
<h1>Image Gallery</h1>
<!-- Carousel -->
<div class="carousel">
<div id="carousel-images">
<!-- Images will be dynamically inserted here -->
</div>
<button class="carousel-button prev" onclick="prevImage()">&#10094;</button>
<button class="carousel-button next" onclick="nextImage()">&#10095;</button>
</div>
<!-- Upload Section -->
<div class="upload-section">
<button class="upload-btn" onclick="document.getElementById('file-input').click()">Upload Image</button>
<input type="file" id="file-input" accept="image/*" style="display: none;" onchange="uploadImage(event)">
</div>
</main>
<!-- Footer Section -->
<div id="footer-container"></div>
<!-- JavaScript -->
<script src="/js/navBar.js"></script>
<script src="/js/footer.js"></script>
<script src="/js/gallery.js"></script>
<script>
// Load header and footer
loadNavbar('navbar-container');
loadFooter('footer-container');
</script>
</body>
</html>
\ No newline at end of file
......@@ -52,6 +52,5 @@
loadFooter('footer-container');
</script>
<script src="/js/rankingTable.js"></script>
<script src="/js/matchSchedule.js"></script>
</body>
</html>
\ No newline at end of file
let currentIndex = 0;
let images = []; // This will hold the URLs of the images
// Load images into the carousel
function loadImages() {
const carouselImages = document.getElementById("carousel-images");
carouselImages.innerHTML = ""; // Clear current images
images.forEach((imageUrl, index) => {
const img = document.createElement("img");
img.src = imageUrl; // Correctly use the URL for the image src
console.log(img.src)
img.alt = `Image ${index + 1}`;
img.style.display = index === currentIndex ? "block" : "none";
carouselImages.appendChild(img);
});
}
// Show previous image
function prevImage() {
currentIndex = (currentIndex - 1 + images.length) % images.length;
loadImages();
}
// Show next image
function nextImage() {
currentIndex = (currentIndex + 1) % images.length;
loadImages();
}
// Upload image
function uploadImage(event) {
const file = event.target.files[0];
if (!file) return;
const formData = new FormData();
formData.append("image", file);
fetch("/api/images", {
method: "POST",
body: formData,
})
.then(response => {
if (!response.ok) {
throw new Error("Failed to upload image");
}
return response.json();
})
.then(data => {
images.push(data.url); // Assuming the server returns the image URL
loadImages();
})
.catch(error => {
console.error("Error uploading image:", error);
});
}
// Initialize the gallery on page load
window.onload = () => {
fetch("/api/images")
.then(response => response.json())
.then(data => {
images = data.map(image => image.url); // Extract URLs from the server response
loadImages();
})
.catch(error => {
console.error("Error loading images:", error);
});
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment