Одна из наиболее распространенных функций веб-приложений при загрузке файлов. Традиционная загрузка файлов требует настройки специальной формы для загрузки файлов. Если взять загрузку изображений в качестве примера, обычный метод заключается в том, чтобы сначала загрузить изображения, затем вернуть адрес изображения и, наконец, использовать картина. Это, несомненно, приведет к серьезной проблеме: если веб-запрос прервется или запрос будет закрыт по другим причинам при последующем использовании образа, то неиспользованные грязные данные останутся на сервере, и их можно будет очистить другим способом. Я называю этот режим проектирования режимом «грубой экономии».Независимо от того, потребляет ли его рынок (бизнес), он будет производиться (загружаться) первым, что в конечном итоге приведет к крайней трате ресурсов. На этот раз я расскажу о другом режиме проектирования, который я называю режимом «экономики, ориентированной на сохранение». алгоритм используется таким образом, двоичный текст синхронно передается в бизнес-метод, и, наконец, файл декодируется и сохраняется для достижения эффекта экономии ресурсов.
основная терминология
1. Кодировка Base64
Кодирование Base64 — это процесс преобразования двоичного кода в символ, который можно использовать для передачи более длинной идентификационной информации в среде HTTP. Например, в системе Java Persistence Hibernate Base64 используется для кодирования длинного уникального идентификатора (обычно 128-битного UUID) в строку, которая используется в качестве параметра в формах HTTP и URL-адресах HTTP GET. В других сценариях приложений часто необходимо кодировать двоичные данные в форму, подходящую для размещения в URL-адресах (включая скрытые поля формы). В настоящее время кодировка Base64 не читается, и ее необходимо декодировать, прежде чем ее можно будет прочитать.
2. Загрузка файла
Загрузка файлов — это передача информации с персонального компьютера (локального компьютера) на центральный сервер (удаленный компьютер) системы для доступа других пользователей в сети. Загрузка файлов делится на загрузку через Интернет и загрузку по FTP. Первая может управляться напрямую, щелкнув ссылку на веб-странице, а для работы последней требуется специальный инструмент FTP.
Анализ случая
Принимая во внимание необходимость добавления статей в качестве примера, статья должна иметь идентификатор, заголовок, обложку, введение, основную часть и другую информацию. Для настройки обложки статьи обычной практикой является асинхронная загрузка изображения на сервер на странице добавления статьи, а затем возврат адреса хранения изображения (URL или URI), привязанного к скрытому полю и одному для предварительного просмотра. , на узле IMG. В настоящее время основная информация статьи не отправлена на сервер, но изображения, относящиеся к статье, поступили на сервер раньше статьи. Хотя это кажется процессом «отчуждения», он всегда кажется «отвратительным». Изначально после смыва унитаза (отправки запроса) и смыва унитаза (отправки транзакции) теперь нужно дополнительно вытирать блевотину на землю (очищать мусорные файлы).
Основываясь на вышеизложенном опыте применения, предлагается использовать кодирование/декодирование Base64 для синхронной загрузки файлов, чтобы изображения статьи поступали на сервер вместе с основной информацией статьи.Если служба неожиданно завершается во время запроса процесс, сервер не будет производить никаких грязных данных. Обсуждено так много потребностей и отправных точек.Далее давайте перейдем к теме этого обмена и посмотрим, как реализовать функцию синхронной загрузки файлов.
Реализация функции
1. Декодер
Нам нужно определить декодер для декодирования двоичных данных изображения, переданных внешним интерфейсом.Как кодировать файл изображения с использованием алгоритма Base64 внешним интерфейсом, будет представлено отдельно в следующем содержании. В настоящее время основной функцией декодера является получение информации о заголовке (метод кодирования) и информации о типе файла в двоичном тексте, закодированном в формате Base64. Затем поле данных декодируется. После завершения декодирования байт-код преобразуется в знакомый объект типа MultipartFile. Код реализации декодера выглядит следующим образом:
package com.ramostear.jfast.common.utils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
/**
* @author ramostear|谭朝红
* @create-time 2019/3/19 0019-23:54
* @modify by :
* @since:
*/
public class Base64Decoder implements MultipartFile{
private final byte[] IMAGE;
private final String HEADER;
private Base64Decoder(byte[]image,String header){
this.IMAGE = image;
this.HEADER = header;
}
public static MultipartFile multipartFile(byte[]image,String header){
return new Base64Decoder(image,header);
}
@Override
public String getName() {
return System.currentTimeMillis()+Math.random()+"."+HEADER.split("/")[1];
}
@Override
public String getOriginalFilename() {
return System.currentTimeMillis()+(int)Math.random()*10000+"."+HEADER.split("/")[1];
}
@Override
public String getContentType() {
return HEADER.split(":")[1];
}
@Override
public boolean isEmpty() {
return IMAGE == null || IMAGE.length == 0;
}
@Override
public long getSize() {
return IMAGE.length;
}
@Override
public byte[] getBytes() throws IOException {
return IMAGE;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(IMAGE);
}
@Override
public void transferTo(File file) throws IOException, IllegalStateException {
new FileOutputStream(file).write(IMAGE);
}
}
2. Преобразователь
Теперь вам нужно определить преобразователь для преобразования информации о символах изображения, переданной из внешнего интерфейса, в массив байтов в кодировке Base64, а затем вызвать декодер, чтобы получить окончательный объект типа MultipartFile. Реализация преобразователя относительно проста, код преобразователя выглядит следующим образом:
package com.ramostear.jfast.common.utils;
import org.springframework.web.multipart.MultipartFile;
import java.util.Base64;
/**
* @author ramostear|谭朝红
* @create-time 2019/3/20 0020-0:00
* @modify by :
* @since:
*/
public class Base64Converter {
public static MultipartFile converter(String source){
String [] charArray = source.split(",");
Base64.Decoder decoder = Base64.getDecoder();
byte[] bytes = new byte[0];
bytes = decoder.decode(charArray[1]);
for (int i=0;i<bytes.length;i++){
if(bytes[i]<0){
bytes[i]+=256;
}
}
return Base64Decoder.multipartFile(bytes,charArray[0]);
}
}
Сосредоточьтесь на методе конвертера:
Во-первых, давайте посмотрим на формат двоичных символов изображения, закодированного на основе алгоритма Base64:
data:image/png;base64,iVBOR....Px1yGQ9EOFXNAAAAAE1FTkSuQmccПоэтому сначала разделите строку на ",", получите информацию заголовка данных ***data:image/png;base64***, а затем перекодируйте основную часть данных через Base64 для получения байтового массива, и наконец Вызовите метод декодирования декодера, чтобы получить объект MultipartFile.
3. Кодировка интерфейса Base64
Основная логика серверной части завершена, теперь мы познакомимся с тем, как интерфейс кодирует изображение с помощью алгоритма Base64.
-
Прежде всего, вам нужно иметь форму для добавления статей и установить поле изображения в скрытое состояние, предоставив узел dom для предварительного просмотра изображения и поле ввода для просмотра локальных изображений.Основной код формы выглядит следующим образом. :
... <form action="/articles" method="POST"> ... <div class="file-preview"> <div class="file-upload-zone"> <div class="file-upload-zone-title">Upload & preview img here …</div> </div> </div> <div class="clearfix"></div> <input type="hidden" name="cover" id="cover"/> <div class="input-group-btn"> <button class="btn btn-blue" type="button" id="upload-btn"> <i class="fa fa-folder-open"></i> <input id="upload-cover" name="upload-cover" multiple="multiple" onchange="fileChange(this)" type="file" accept="image/*"/> </button> </div> ... </form> ... -
Затем определите метод fileChange для обработки кодировки файла, код выглядит следующим образом:
function fileChange(obj){ try{ var file = obj.files[0]; var reader = new FileReader(); var fileName=""; if(typeof(fileName) != "undefined"){ fileName = $(obj).val().split("\\").pop(); } reader.onload = function(){ var img = new Image(); img.src = reader.result; img.onload = function(){ var w = img.width,h = img.height; var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); $(canvas).attr({ width:w, height:h }); ctx.drawImage(img,0,0,w,h); var base64 = canvas.toDataURL("image/png",0.5); var result = { url:window.URL.createObjectURL(file), base64:base64, clearBase64:base64.substr(base64.indexOf(',')+1), suffix:base64.substring(base64.indexOf(',')+1,base64.indexOf(';')) }; $(".file-upload-zone-title").hide(); $(".file-upload-zone").empty(); $("#cover").val(result.base64); $("<img src=\""+result.base64+"\" class=\"img img-responsive center-block\">").appendTo(".file-upload-zone"); $(".file-upload-zone").trigger("create"); $(".file-name").val(fileName); } } reader.readAsDataURL(obj.files[0]); }catch(e){ layer.msg("error"); } };
Что касается основной логики этого кода, то на самом деле он противоположен процессу декодирования в серверной части, поэтому я не буду здесь вдаваться в подробности.
На данный момент основная функция синхронной загрузки файлов с помощью кодировки Base64 выполнена.В следующем контенте Spring Boot 2.0 используется для быстрой демонстрации контента, которым на этот раз поделились.
Добавить сервисный компонент статьи#загрузка файла
1. Добавьте служебную составляющую статьи
Следуя фону требования с самого начала, информация об изображении принадлежит значению атрибута объекта статьи, поэтому логика для обработки загрузки файла размещена в службе.В этом тестовом коде окончательное хранилище файлов использует службу CDN Qiniuyun. . Код для части CDN не расширяется и может быть загружен локально. Объектами обеих операций являются MultipartFile, и способ хранения не является предметом этого совместного использования. Основной код сервисного компонента статьи выглядит следующим образом:
package com.ramostear.jfast.domain.service.impl;
import com.ramostear.jfast.common.ext.Translate;
import com.ramostear.jfast.domain.repo.ArticleRepo;
import com.ramostear.jfast.domain.service.ArticleService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author ramostear|谭朝红
* @create-time 2019/3/19 0019-23:37
* @modify by :
* @since:
*/
@Service(value = "articleService")
@Transactional(readOnly = true)
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleRepo articleRepo;
@Override
@Transactional
public void save(ArticleVo vo) {
Article article = Translate.toArticle(vo);
articleRepo.save(article);
}
В сервисном компоненте ArticleService задействован класс Translate, его функция заключается в отображении ValueObject, передаваемого из фронтенда, в класс POJO, а также инкапсуляция логики хранения файлов, основной код выглядит следующим образом:
package com.ramostear.jfast.common.ext;
import com.ramostear.jfast.common.factory.CdnFactory;
import com.ramostear.jfast.common.factory.cdn.CdnRepository;
import com.ramostear.jfast.common.utils.Base64Converter;
import com.ramostear.jfast.domain.model.Article;
import com.ramostear.jfast.domain.vo.ArticleVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.web.multipart.MultipartFile;
import java.util.Date;
/**
* @author ramostear|谭朝红
* @create-time 2019/3/18 0018-3:39
* @modify by :
* @since:
*/
public class Translate {
private static CdnRepository cdnRepo = CdnFactory.builder(CdnFactory.CdnType.Qiniu);
public static Article toArticle(ArticleVo vo){
Article article = new Article();
BeanUtils.copyProperties(vo,article);
if(StringUtils.isNotBlank(vo.getCover())){
MultipartFile file = Base64Converter.converter(vo.getCover());
article.setCover(cdnRepo.save(file));
}
return article;
}
}
Поскольку здесь используется служба CDN Qiniu Cloud, экземпляр хранилища CND получается через класс фабрики CND, который используется для записи файлов в хранилище и возврата адреса доступа к файлу. В дополнение к вышеуказанным методам вы также можете вызвать метод file.transferTo() для записи файла на локальный (сервер приложений) диск.
Детали реализации фабричного класса CND здесь не расширены из-за недостатка места. Если вам нужно узнать больше о том, как использовать CDN SDK, вы можете оставить мне сообщение в конце статьи.
2. Контроллер статей
Наконец, определите контроллер, который будет вызываться при добавлении статей во внешний интерфейс. Основная задача контроллера статей — получить информацию о статье, переданную внешним интерфейсом, а затем вызвать компонент службы статей для завершения работы по добавлению статей. . Основной код выглядит следующим образом:
package com.ramostear.jfast.domain.controller;
@RestController
public class ArticleController{
@Autowired
ArticleService articleService;
@Postmapping(value="/articles")
public ResponseEntity<Object> createArticle(@RequestBody ArticleVo vo){
try{
articleService.save(vo);
return new ResponseEntity<>("已经成功将文字写入数据库",HttpStatus.CREATED);
}catch(Exception e){
return new ResponseEntity<>(e.getMessage(),HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
заключительные замечания
Этот обмен дает только реализацию основных частей, а задействованные знания, такие как CDN, HTML, JS и т. д., не были расширены.Если вы запутались, вы можете оставить сообщение в области комментариев, и мы обсудим это. вместе. Еще раз спасибо за чтение, спасибо~~~
Перепечатайте, пожалуйста, сохраните информацию об авторских правах и не используйте ее в коммерческих целях.
Автор: Тан Чаохун, оригинальное название:Анализ технологии загрузки файлов Spring Boot на основе алгоритма кодирования/декодирования Base64