#7 -- fix image operations

This commit is contained in:
Anton Romanov 2022-03-14 17:03:21 +04:00
parent 6a553a3330
commit a09528cdfb
19 changed files with 223 additions and 9 deletions

Binary file not shown.

View File

@ -3,10 +3,12 @@ package ru.ulstu;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import ru.ulstu.user.UserService; import ru.ulstu.user.UserService;
@SpringBootApplication @SpringBootApplication
@EnableConfigurationProperties
public class SeminarApplication { public class SeminarApplication {
private final UserService userService; private final UserService userService;

View File

@ -45,7 +45,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
log.debug("Security enabled"); log.debug("Security enabled");
http.authorizeRequests() http.authorizeRequests()
.antMatchers("/").permitAll() .antMatchers("/").permitAll()
.antMatchers("/login", "/index", "/news/**", "/meetings/**", "/h2-console/*", "/h2-console").permitAll() .antMatchers("/login", "/index", "/news/**", "/meetings/**", "/files/**", "/h2-console/*", "/h2-console").permitAll()
.antMatchers("/swagger-ui.html").hasAuthority(UserRoleConstants.ADMIN) .antMatchers("/swagger-ui.html").hasAuthority(UserRoleConstants.ADMIN)
.anyRequest().authenticated() .anyRequest().authenticated()
.and() .and()

View File

@ -0,0 +1,80 @@
package ru.ulstu.files;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
@Service
public class FileSystemStorageService implements StorageService {
public static final String UPLOAD_DIR = "upload";
private final Path rootLocation = Paths.get(UPLOAD_DIR);
@Override
public void store(MultipartFile file) {
try {
if (file.isEmpty()) {
throw new StorageException("Failed to store empty file " + file.getOriginalFilename());
}
Files.copy(file.getInputStream(), this.rootLocation.resolve(file.getOriginalFilename()));
} catch (IOException e) {
throw new StorageException("Failed to store file " + file.getOriginalFilename(), e);
}
}
@Override
public Stream<Path> loadAll() {
try {
return Files.walk(this.rootLocation, 1)
.filter(path -> !path.equals(this.rootLocation))
.map(path -> this.rootLocation.relativize(path));
} catch (IOException e) {
throw new StorageException("Failed to read stored files", e);
}
}
@Override
public Path load(String filename) {
return rootLocation.resolve(filename);
}
@Override
public Resource loadAsResource(String filename) {
try {
Path file = load(filename);
Resource resource = new UrlResource(file.toUri());
if (resource.exists() || resource.isReadable()) {
return resource;
} else {
throw new StorageFileNotFoundException("Could not read file: " + filename);
}
} catch (MalformedURLException e) {
throw new StorageFileNotFoundException("Could not read file: " + filename, e);
}
}
@Override
public void deleteAll() {
FileSystemUtils.deleteRecursively(rootLocation.toFile());
}
@Override
public void init() {
try {
Files.createDirectory(rootLocation);
} catch (IOException e) {
throw new StorageException("Could not initialize storage", e);
}
}
}

View File

@ -1,4 +1,4 @@
package ru.ulstu.service; package ru.ulstu.files;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;

View File

@ -0,0 +1,28 @@
package ru.ulstu.files;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class FilesController {
private final StorageService storageService;
public FilesController(StorageService storageService) {
this.storageService = storageService;
}
@GetMapping("/files/{filename:.+}")
@ResponseBody
public ResponseEntity<Resource> serveFile(@PathVariable String filename) {
Resource file = storageService.loadAsResource((filename == null || filename.equals("null") || filename.isEmpty())
? "logo.png"
: filename);
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
"filename=\"" + file.getFilename() + "\"").body(file);
}
}

View File

@ -0,0 +1,12 @@
package ru.ulstu.files;
public class StorageException extends RuntimeException {
public StorageException(String message) {
super(message);
}
public StorageException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,12 @@
package ru.ulstu.files;
public class StorageFileNotFoundException extends StorageException {
public StorageFileNotFoundException(String message) {
super(message);
}
public StorageFileNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,23 @@
package ru.ulstu.files;
import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Path;
import java.util.stream.Stream;
public interface StorageService {
void init();
void store(MultipartFile file);
Stream<Path> loadAll();
Path load(String filename);
Resource loadAsResource(String filename);
void deleteAll();
}

View File

@ -3,7 +3,8 @@ package ru.ulstu.news;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.ulstu.service.FileUtil; import ru.ulstu.files.FileSystemStorageService;
import ru.ulstu.files.FileUtil;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.IOException; import java.io.IOException;
@ -37,9 +38,7 @@ public class NewsService {
create(news); create(news);
} }
String uploadDir = "news-photos/"; FileUtil.saveFile(FileSystemStorageService.UPLOAD_DIR, fileName, news.getImageFile());
FileUtil.saveFile(uploadDir, fileName, news.getImageFile());
} }
public News getById(@NotNull Integer id) { public News getById(@NotNull Integer id) {

View File

@ -11,7 +11,7 @@
<div th:each="n : ${news}" class="news"> <div th:each="n : ${news}" class="news">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<img class="news-image" src="/img/logo.svg"/> <img class="news-image" th:src="@{'/files/' + ${n.imageFileName}}"/>
</div> </div>
<div class="col-md-8"> <div class="col-md-8">
<div class="row"> <div class="row">

View File

@ -12,7 +12,7 @@
<div th:each="n : ${news}" class="news"> <div th:each="n : ${news}" class="news">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<img class="news-image" src="/img/logo.svg"/> <img class="news-image" th:src="@{'/files/' + ${n.imageFileName}}"/>
</div> </div>
<div class="col-md-8"> <div class="col-md-8">
<div class="row"> <div class="row">

View File

@ -11,7 +11,7 @@
<div class="container" layout:fragment="content"> <div class="container" layout:fragment="content">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<img class="news-image" src="/img/logo.svg"/> <img class="news-image" th:src="@{'/files/' + ${news.imageFileName}}"/>
</div> </div>
<div class="col-md-8"> <div class="col-md-8">
<h5 th:text="${news.title}"/> <h5 th:text="${news.title}"/>

BIN
upload/1647261445926 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
upload/1647262081164 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

58
upload/1647262775259 Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="1000"
height="1000"
viewBox="0 0 500 500"
xml:space="preserve"
id="svg45"
sodipodi:docname="IS_logo_black.svg"
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview47"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="true"
showgrid="false"
showborder="false"
inkscape:zoom="0.769"
inkscape:cx="500"
inkscape:cy="500"
inkscape:window-width="1920"
inkscape:window-height="991"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg45" />
<desc
id="desc29">Created with Fabric.js 4.6.0</desc>
<defs
id="defs31">
</defs>
<path
id="path33"
style="fill:#000000;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
d="M 614.48828 177.41406 C 585.03403 177.64615 555.102 180 528 180 C 509.268 180 474.11592 173.20281 457.41992 181.83789 C 441.12592 190.26483 422.34 188.47467 404 190.33789 C 365.3278 194.26683 326.787 197.16411 288 199.82031 C 261.38 201.64331 230.50279 201.95901 212.77539 226.25781 C 196.16547 249.02541 217.5264 250.08661 219.7832 270.00781 C 223.4616 302.47861 220 337.3084 220 370 C 220 424.688 216.64862 482.378 228.69922 536 C 234.13282 560.178 241.07448 585.21445 258.58008 603.81445 C 286.96128 633.96645 327.183 628.83584 364 632.33984 C 434.958 639.09184 507.266 629.02169 578 624.17969 C 620.728 621.25169 671.094 620.42538 710 600.35938 C 785.886 561.21938 770.028 472.564 770 402 C 769.978 343.7938 783.18837 263.01536 746.73438 213.03516 C 735.77437 198.01096 714.65742 193.13757 698.10742 187.56055 C 672.91842 179.07202 643.94253 177.18197 614.48828 177.41406 z M 451.28516 278.24414 C 508.18157 277.94477 575.51534 292.60888 617.99609 321.03906 C 665.52009 352.84446 673.38009 409.60016 625.99609 446.66016 C 609.19809 459.79816 583.47409 470.56595 561.99609 465.75195 C 553.62409 463.87395 546.58609 456.87805 537.99609 456.49805 C 522.09609 455.79605 512.77609 463.8217 495.99609 456.5957 C 476.36009 448.1397 462.80717 414.5508 471.20117 394.2168 C 474.36317 386.5588 491.70145 379.35103 497.93945 387.20703 C 508.38745 400.36503 494.40964 432.52702 516.18164 440.79102 C 530.60964 446.26702 534.58192 411.00817 555.66992 414.32617 C 563.02792 415.48417 559.99497 424.656 562.04297 430 C 565.00297 437.722 572.19609 445.56767 579.99609 448.51367 C 613.82609 461.29167 642.2743 406.694 629.9043 380 C 614.3683 346.4774 578.65809 326.98059 545.99609 313.90039 C 482.01609 288.27899 396.70598 263.8648 347.51758 330 C 318.46498 369.0616 331.97353 426.708 360.51953 462 C 409.14233 522.116 497.53009 557.79392 573.99609 553.91992 C 589.34209 553.14192 620.65517 534.20281 630.95117 522.88281 C 639.49717 513.48281 642.08522 495.18492 661.69922 503.79492 C 677.95722 510.93492 656.70214 530.07166 649.99414 535.34766 C 623.11814 556.49766 583.00409 562 549.99609 562 C 468.35409 562 372.36956 530.03 324.10156 460 C 268.98216 380.028 324.58909 293.80382 413.99609 280.85742 C 425.58059 279.17993 438.15521 278.31323 451.28516 278.24414 z "
transform="scale(0.5)" />
<path
id="path39"
style="fill:#000000;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
d="M 668.33594 643.47656 C 662.50706 643.55654 656.40463 644.00634 650 644.84766 C 557.68 656.97566 466.83 659.8418 374 659.8418 C 334.445 659.8418 285.9012 644.14103 248 660.95703 C 236.5832 666.02303 220.35223 674.28205 214.67383 685.99805 C 208.78323 698.15205 227.05259 701.474 224.27539 714 C 219.13139 737.202 163.19081 780.43105 192.00977 796.62305 C 213.03631 808.43705 243.23832 802.31272 265.85352 808.63672 C 272.15212 810.39872 271.30588 817.50928 276.70508 819.36328 C 297.12228 826.37328 330.3592 820 352 820 L 522 820 C 564.108 820 614.34895 827.63112 655.62695 819.70312 C 662.58095 818.36712 661.85506 809.62887 670.03906 808.29688 C 720.71106 800.04488 767.32912 814.45956 813.70312 783.85156 C 829.97513 773.11156 793.83588 738.344 786.17188 726 C 755.44819 676.52238 724.68174 642.70346 668.33594 643.47656 z M 632.96094 696.08594 C 656.9772 696.33526 670.5987 710.58 684.6582 732 C 687.2762 735.988 699.90202 751.25736 696.16602 755.94336 C 692.75802 760.21936 680.742 757.31823 676 757.49023 C 655.976 758.22223 636.016 761.75419 616 761.99219 C 537.304 762.92819 456.724 769.21231 378 763.82031 C 355.2814 762.26631 332.628 759.24231 310 756.57031 C 305.7648 756.07031 289.0863 758.23892 287.8125 752.79492 C 284.9009 740.34892 309.79135 708.10719 322.00195 708.11719 C 423.72835 708.20119 520.668 711.33947 622 696.85547 C 625.88675 696.29997 629.53004 696.05032 632.96094 696.08594 z "
transform="scale(0.5)" />
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

0
upload/1647262911771 Normal file
View File

0
upload/1647262925015 Normal file
View File

BIN
upload/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB