优化
This commit is contained in:
@@ -81,6 +81,24 @@ public class PlatformMeasurementImageController {
|
||||
.body(image.content());
|
||||
}
|
||||
|
||||
@GetMapping("/{tenantId}/{inboundId}/{fileId}/thumbnail")
|
||||
@PreAuthorize("hasAuthority('platform:firstleg:inbound:measure:view')")
|
||||
@Operation(summary = "查看入库单称重图片缩略图")
|
||||
public ResponseEntity<byte[]> thumbnail(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@PathVariable long tenantId,
|
||||
@PathVariable long inboundId,
|
||||
@PathVariable long fileId) {
|
||||
requirePlatform(user);
|
||||
requirePositive(tenantId, inboundId, fileId);
|
||||
var image = images.thumbnail(tenantId, inboundId, fileId);
|
||||
return ResponseEntity.ok()
|
||||
.cacheControl(CacheControl.noStore())
|
||||
.contentType(MediaType.IMAGE_JPEG)
|
||||
.contentLength(image.content().length)
|
||||
.body(image.content());
|
||||
}
|
||||
|
||||
private long requirePlatform(AuthenticatedUser user) {
|
||||
if (user == null || !"PLATFORM".equalsIgnoreCase(user.appCode())
|
||||
|| user.tenantId() == null || user.tenantId() != 0L
|
||||
|
||||
@@ -15,11 +15,19 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
@Service
|
||||
public class MeasurementImageService {
|
||||
@@ -81,11 +89,45 @@ public class MeasurementImageService {
|
||||
return new Download(object.getOriginalName(), object.getContentType(), storage.read(object.getObjectKey()));
|
||||
}
|
||||
|
||||
public Download thumbnail(long tenantId, long inboundId, long fileId) {
|
||||
Download original = download(tenantId, inboundId, fileId);
|
||||
try {
|
||||
BufferedImage source = ImageIO.read(new ByteArrayInputStream(original.content()));
|
||||
if (source == null) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "称重图片无法生成缩略图");
|
||||
}
|
||||
double scale = Math.min(1D, Math.min(480D / source.getWidth(), 320D / source.getHeight()));
|
||||
int width = Math.max(1, (int) Math.round(source.getWidth() * scale));
|
||||
int height = Math.max(1, (int) Math.round(source.getHeight() * scale));
|
||||
BufferedImage target = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D graphics = target.createGraphics();
|
||||
try {
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.fillRect(0, 0, width, height);
|
||||
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
graphics.setRenderingHint(RenderingHints.KEY_RENDERING,
|
||||
RenderingHints.VALUE_RENDER_QUALITY);
|
||||
graphics.drawImage(source, 0, 0, width, height, null);
|
||||
} finally {
|
||||
graphics.dispose();
|
||||
}
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
if (!ImageIO.write(target, "jpg", output)) {
|
||||
throw new BizException(ResultCode.INTERNAL_ERROR, "称重图片缩略图编码失败");
|
||||
}
|
||||
return new Download("thumbnail.jpg", "image/jpeg", output.toByteArray());
|
||||
} catch (IOException exception) {
|
||||
throw new BizException(ResultCode.INTERNAL_ERROR, "称重图片缩略图生成失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteMeasurementEvidence(long tenantId, long inboundId, long fileId, long operatorId) {
|
||||
FileObjectEntity object = requireObject(tenantId, inboundId, fileId);
|
||||
if (!"INBOUND_MEASUREMENT_IMAGE".equals(object.getBusinessType())) {
|
||||
throw new BizException(ResultCode.CONFLICT, "仅允许清理第三方尺寸测量证据图片");
|
||||
if (!Set.of("INBOUND_WEIGHT_IMAGE", "INBOUND_MEASUREMENT_IMAGE")
|
||||
.contains(object.getBusinessType())) {
|
||||
throw new BizException(ResultCode.CONFLICT, "仅允许清理入库测量图片");
|
||||
}
|
||||
object.setStatus("DELETED");
|
||||
object.setUpdatedBy(operatorId);
|
||||
|
||||
+12
@@ -10,6 +10,7 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
@@ -71,4 +72,15 @@ class PlatformMeasurementImageControllerContractTest {
|
||||
assertThatThrownBy(() -> controller.upload(malformed, 10001L, 88L, file))
|
||||
.isInstanceOf(BizException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void thumbnailUsesViewPermission() throws Exception {
|
||||
Method method = PlatformMeasurementImageController.class.getDeclaredMethod("thumbnail",
|
||||
AuthenticatedUser.class, long.class, long.class, long.class);
|
||||
|
||||
assertThat(method.getAnnotation(GetMapping.class).value())
|
||||
.containsExactly("/{tenantId}/{inboundId}/{fileId}/thumbnail");
|
||||
assertThat(method.getAnnotation(PreAuthorize.class).value())
|
||||
.isEqualTo("hasAuthority('platform:firstleg:inbound:measure:view')");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ import jakarta.annotation.Resource;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.math.BigDecimal;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@@ -137,6 +141,38 @@ class MeasurementImageServiceEvidenceTest {
|
||||
ordered.verify(storage).delete(object.getObjectKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deletesWeightImageThroughTheSameOwnedFileBoundary() {
|
||||
FileObjectEntity object = measurementEvidence();
|
||||
object.setBusinessType("INBOUND_WEIGHT_IMAGE");
|
||||
when(files.selectOne(any())).thenReturn(object);
|
||||
when(files.updateById(object)).thenReturn(1);
|
||||
when(files.deleteById(41L)).thenReturn(1);
|
||||
|
||||
service.deleteMeasurementEvidence(11L, 21L, 41L, 31L);
|
||||
|
||||
verify(storage).delete(object.getObjectKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsBoundedJpegThumbnail() throws Exception {
|
||||
FileObjectEntity object = measurementEvidence();
|
||||
object.setOriginalName("weight.png");
|
||||
object.setContentType(MediaType.IMAGE_PNG_VALUE);
|
||||
when(files.selectOne(any())).thenReturn(object);
|
||||
BufferedImage source = new BufferedImage(1200, 800, BufferedImage.TYPE_INT_RGB);
|
||||
ByteArrayOutputStream image = new ByteArrayOutputStream();
|
||||
ImageIO.write(source, "png", image);
|
||||
when(storage.read(object.getObjectKey())).thenReturn(image.toByteArray());
|
||||
|
||||
MeasurementImageService.Download result = service.thumbnail(11L, 21L, 41L);
|
||||
|
||||
BufferedImage thumbnail = ImageIO.read(new java.io.ByteArrayInputStream(result.content()));
|
||||
assertThat(result.contentType()).isEqualTo(MediaType.IMAGE_JPEG_VALUE);
|
||||
assertThat(thumbnail.getWidth()).isEqualTo(480);
|
||||
assertThat(thumbnail.getHeight()).isEqualTo(320);
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotDeleteStoredContentWhenLogicalDeleteLosesTheRace() {
|
||||
FileObjectEntity object = measurementEvidence();
|
||||
|
||||
Reference in New Issue
Block a user