Compare commits
No commits in common. "master" and "v0.0.1" have entirely different histories.
4
.gitignore
vendored
4
.gitignore
vendored
@ -22,6 +22,4 @@
|
|||||||
/nbbuild/
|
/nbbuild/
|
||||||
/dist/
|
/dist/
|
||||||
/nbdist/
|
/nbdist/
|
||||||
/.nb-gradle/
|
/.nb-gradle/
|
||||||
|
|
||||||
/.vscode/
|
|
15
Dockerfile
15
Dockerfile
@ -1,15 +0,0 @@
|
|||||||
FROM debian:stable-slim
|
|
||||||
RUN apt-get update
|
|
||||||
RUN apt-get -y upgrade
|
|
||||||
RUN mkdir /upload /usr/share/man/man1 /usr/share/man/man8
|
|
||||||
RUN apt-get -y install --no-install-recommends apt apt-transport-https apt-utils readline-common curl gnupg software-properties-common dirmngr openjdk-8-jdk procps
|
|
||||||
RUN echo "deb https://artifacts.elastic.co/packages/6.x/apt stable main" > /etc/apt/sources.list.d/elastic-6.x.list
|
|
||||||
RUN apt-key adv --recv-keys D27D666CD88E42B4
|
|
||||||
RUN apt-get update
|
|
||||||
RUN apt-get -y install --no-install-recommends maven tesseract-ocr tesseract-ocr-spa elasticsearch git
|
|
||||||
RUN sed -i "s/#cluster.name: my-application/cluster.name: elasticsearch/" /etc/elasticsearch/elasticsearch.yml
|
|
||||||
RUN git clone https://gitlab.com/manalejandro/arjion
|
|
||||||
RUN mvn clean install -f /arjion/pom.xml
|
|
||||||
RUN echo "/etc/init.d/elasticsearch start && mvn spring-boot:run -f /arjion/pom.xml" > entrypoint.sh
|
|
||||||
EXPOSE 8080:8080
|
|
||||||
ENTRYPOINT ["bash", "entrypoint.sh"]
|
|
@ -4,11 +4,6 @@
|
|||||||
|
|
||||||
### Proof of Concept with [SpringBoot 2.1.0](https://start.spring.io/), [ElasticSearch](https://www.elastic.co/) and [Apache Tika](https://tika.apache.org/)
|
### Proof of Concept with [SpringBoot 2.1.0](https://start.spring.io/), [ElasticSearch](https://www.elastic.co/) and [Apache Tika](https://tika.apache.org/)
|
||||||
|
|
||||||
## Docker image
|
|
||||||
|
|
||||||
$ docker build -t debian:arjion --rm https://gitlab.com/manalejandro/arjion/raw/master/Dockerfile
|
|
||||||
$ docker run -ti -p 8080:8080 debian:arjion
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
40
pom.xml
40
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>com.manalejandro</groupId>
|
<groupId>com.manalejandro</groupId>
|
||||||
<artifactId>arjion</artifactId>
|
<artifactId>arjion</artifactId>
|
||||||
<version>0.2.0-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<packaging>war</packaging>
|
<packaging>war</packaging>
|
||||||
|
|
||||||
<name>arjion</name>
|
<name>arjion</name>
|
||||||
@ -45,38 +45,14 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- https://mvnrepository.com/artifact/org.apache.tika/tika-app -->
|
<!-- https://mvnrepository.com/artifact/org.apache.tika/tika -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.tika</groupId>
|
<groupId>org.apache.tika</groupId>
|
||||||
<artifactId>tika-app</artifactId>
|
<artifactId>tika</artifactId>
|
||||||
<version>1.18</version>
|
<version>1.18</version>
|
||||||
</dependency>
|
<type>pom</type>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.tika</groupId>
|
|
||||||
<artifactId>tika-parsers</artifactId>
|
|
||||||
<version>1.18</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- https://mvnrepository.com/artifact/com.github.jai-imageio/jai-imageio-jpeg2000 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.jai-imageio</groupId>
|
|
||||||
<artifactId>jai-imageio-jpeg2000</artifactId>
|
|
||||||
<version>1.3.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.levigo.jbig2</groupId>
|
|
||||||
<artifactId>levigo-jbig2-imageio</artifactId>
|
|
||||||
<version>2.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.jai-imageio</groupId>
|
|
||||||
<artifactId>jai-imageio-core</artifactId>
|
|
||||||
<version>1.4.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.webjars</groupId>
|
<groupId>org.webjars</groupId>
|
||||||
<artifactId>bootstrap</artifactId>
|
<artifactId>bootstrap</artifactId>
|
||||||
|
@ -9,12 +9,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|||||||
@EnableWebMvc
|
@EnableWebMvc
|
||||||
public class WebConfig implements WebMvcConfigurer {
|
public class WebConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
|
@Override
|
||||||
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
|
registry.addResourceHandler("/webjars/**").addResourceLocations("/webjars/");
|
||||||
@Override
|
}
|
||||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
|
||||||
registry.addResourceHandler("/webjars/**").addResourceLocations("/webjars/");
|
|
||||||
registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,165 +1,14 @@
|
|||||||
package com.manalejandro.arjion.controllers;
|
package com.manalejandro.arjion.controllers;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.text.Normalizer;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.manalejandro.arjion.model.Archivo;
|
|
||||||
import com.manalejandro.arjion.model.Documento;
|
|
||||||
import com.manalejandro.arjion.services.MainService;
|
|
||||||
import com.manalejandro.arjion.vo.DetailVO;
|
|
||||||
import com.manalejandro.arjion.vo.DocumentoVO;
|
|
||||||
|
|
||||||
import org.apache.tika.config.TikaConfig;
|
|
||||||
import org.apache.tika.exception.TikaException;
|
|
||||||
import org.apache.tika.io.TikaInputStream;
|
|
||||||
import org.apache.tika.language.LanguageIdentifier;
|
|
||||||
import org.apache.tika.metadata.Metadata;
|
|
||||||
import org.apache.tika.parser.AutoDetectParser;
|
|
||||||
import org.apache.tika.parser.ParseContext;
|
|
||||||
import org.apache.tika.parser.Parser;
|
|
||||||
import org.apache.tika.parser.ocr.TesseractOCRConfig;
|
|
||||||
import org.apache.tika.parser.pdf.PDFParserConfig;
|
|
||||||
import org.apache.tika.sax.BodyContentHandler;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.core.io.ByteArrayResource;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
import org.xml.sax.ContentHandler;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class MainController {
|
public class MainController {
|
||||||
|
|
||||||
private final MainService mainService;
|
@RequestMapping(path = "/")
|
||||||
|
public String indexPage(final Model model) {
|
||||||
@Value("${arjion.uploadpath}")
|
return "index";
|
||||||
private String uploadpath;
|
}
|
||||||
|
}
|
||||||
@Value("${arjion.tesseractpath}")
|
|
||||||
private String tesseractpath;
|
|
||||||
|
|
||||||
@Value("${arjion.tesseractdatapath}")
|
|
||||||
private String tesseractdatapath;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public MainController(MainService mainService) {
|
|
||||||
this.mainService = mainService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping(path = "/")
|
|
||||||
public String indexPage(final Model model) {
|
|
||||||
DocumentoVO documentoVO = new DocumentoVO();
|
|
||||||
documentoVO.setCount(mainService.count());
|
|
||||||
documentoVO.setDocumentos(mainService.findAllDocumento());
|
|
||||||
model.addAttribute("documentoVO", documentoVO);
|
|
||||||
return "index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping(path = "/upload")
|
|
||||||
public String upload() {
|
|
||||||
return "redirect:/";
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping(path = "/upload")
|
|
||||||
public String uploadPage(final Model model, @RequestParam("archivos") MultipartFile[] archivos)
|
|
||||||
throws IOException, TikaException, SAXException {
|
|
||||||
DocumentoVO documentoVO = new DocumentoVO();
|
|
||||||
documentoVO.setCount(mainService.count());
|
|
||||||
documentoVO.setDocumentos(mainService.findAllDocumento());
|
|
||||||
if (archivos.length > 0) {
|
|
||||||
// Recupera la configuración de Tika
|
|
||||||
TikaConfig tikaConfig = TikaConfig.getDefaultConfig();
|
|
||||||
// Itera los archivos recibidos
|
|
||||||
for (int i = 0; i < archivos.length; i++) {
|
|
||||||
byte[] bytes = archivos[i].getBytes();
|
|
||||||
// Normaliza el título de los archivos
|
|
||||||
String normalized = Normalizer.normalize(archivos[i].getOriginalFilename(), Normalizer.Form.NFD),
|
|
||||||
filename = normalized.replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
|
|
||||||
Path path = Paths.get(uploadpath + filename);
|
|
||||||
// Instancias necesarias
|
|
||||||
Metadata metadata = new Metadata();
|
|
||||||
Parser parser = new AutoDetectParser(tikaConfig);
|
|
||||||
PDFParserConfig pdfConfig = new PDFParserConfig();
|
|
||||||
TesseractOCRConfig tesseractConfig = new TesseractOCRConfig();
|
|
||||||
tesseractConfig.setTesseractPath(tesseractpath);
|
|
||||||
tesseractConfig.setTessdataPath(tesseractdatapath);
|
|
||||||
tesseractConfig.setLanguage("spa+eng");
|
|
||||||
pdfConfig.setExtractInlineImages(true);
|
|
||||||
ParseContext parseContext = new ParseContext();
|
|
||||||
parseContext.set(TesseractOCRConfig.class, tesseractConfig);
|
|
||||||
parseContext.set(PDFParserConfig.class, pdfConfig);
|
|
||||||
// Usa -1 para no tener límite de 100000 chars
|
|
||||||
ContentHandler handler = new BodyContentHandler(-1);
|
|
||||||
// Castea los bytes al Stream de Tika
|
|
||||||
TikaInputStream stream = TikaInputStream.get(bytes);
|
|
||||||
// Parsea el contenido
|
|
||||||
parser.parse(stream, handler, metadata, parseContext);
|
|
||||||
// Identifica el idioma del archivo
|
|
||||||
LanguageIdentifier identifier = new LanguageIdentifier(handler.toString());
|
|
||||||
// Almacena en elasticsearch
|
|
||||||
String[] names = metadata.names();
|
|
||||||
Map<String, String> meta = new HashMap<String, String>();
|
|
||||||
for (int j = 0; j < names.length; j++) {
|
|
||||||
meta.put(names[j], metadata.get(names[j]));
|
|
||||||
}
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
if (!mainService.save(new Documento(filename, Long.valueOf(archivos[i].getSize()).intValue(),
|
|
||||||
mapper.valueToTree(meta), handler.toString(), identifier.getLanguage()))) {
|
|
||||||
return "exists";
|
|
||||||
} else {
|
|
||||||
// Guarda el archivo en el directorio configurado en las properties
|
|
||||||
Files.write(path, bytes);
|
|
||||||
}
|
|
||||||
// Añade los parámetros al VO para mostrar en la vista
|
|
||||||
documentoVO.getArchivos().add(new Archivo(filename, Long.valueOf(archivos[i].getSize()).intValue(), meta,
|
|
||||||
handler.toString(), identifier.getLanguage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
model.addAttribute("documentoVO", documentoVO);
|
|
||||||
return "index";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping(path = "/detail")
|
|
||||||
public String detail(final Model model, @RequestParam(value = "nombre", required = true) String nombre) {
|
|
||||||
DetailVO detailVO = new DetailVO();
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
Documento doc = mainService.findOne(nombre);
|
|
||||||
detailVO.setArchivo(new Archivo(doc.getNombre(), doc.getTamano(),
|
|
||||||
mapper.convertValue(doc.getMetadata(), Map.class), doc.getContenido(), doc.getLenguaje()));
|
|
||||||
model.addAttribute("detailVO", detailVO);
|
|
||||||
return "detail";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping(path = "/download")
|
|
||||||
public ResponseEntity<ByteArrayResource> download(final HttpServletResponse response,
|
|
||||||
@RequestParam(value = "filename", required = true) String filename)
|
|
||||||
throws IOException, MalformedURLException {
|
|
||||||
File file = new File(uploadpath + filename);
|
|
||||||
Path path = Paths.get(file.getAbsolutePath());
|
|
||||||
ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(path));
|
|
||||||
String type = file.toURL().openConnection().guessContentTypeFromName(filename);
|
|
||||||
HttpHeaders responseHeaders = new HttpHeaders();
|
|
||||||
responseHeaders.add("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
|
|
||||||
responseHeaders.add("Content-Type", type);
|
|
||||||
return ResponseEntity.ok().contentLength(file.length()).headers(responseHeaders).body(resource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
package com.manalejandro.arjion.model;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class Archivo {
|
|
||||||
|
|
||||||
private String nombre;
|
|
||||||
private Integer tamano;
|
|
||||||
private Map metadata;
|
|
||||||
private String contenido;
|
|
||||||
private String lenguaje;
|
|
||||||
|
|
||||||
public Archivo(String nombre, Integer tamano, Map metadata, String contenido, String lenguaje) {
|
|
||||||
this.nombre = nombre;
|
|
||||||
this.tamano = tamano;
|
|
||||||
this.metadata = metadata;
|
|
||||||
this.contenido = contenido;
|
|
||||||
this.lenguaje = lenguaje;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the nombre
|
|
||||||
*/
|
|
||||||
public String getNombre() {
|
|
||||||
return nombre;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the tamano
|
|
||||||
*/
|
|
||||||
public Integer getTamano() {
|
|
||||||
return tamano;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the metadata
|
|
||||||
*/
|
|
||||||
public Map getMetadata() {
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the contenido
|
|
||||||
*/
|
|
||||||
public String getContenido() {
|
|
||||||
return contenido;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param nombre the nombre to set
|
|
||||||
*/
|
|
||||||
public void setNombre(String nombre) {
|
|
||||||
this.nombre = nombre;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param tamano the tamano to set
|
|
||||||
*/
|
|
||||||
public void setTamano(Integer tamano) {
|
|
||||||
this.tamano = tamano;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param metadata the metadata to set
|
|
||||||
*/
|
|
||||||
public void setMetadata(Map metadata) {
|
|
||||||
this.metadata = metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param contenido the contenido to set
|
|
||||||
*/
|
|
||||||
public void setContenido(String contenido) {
|
|
||||||
this.contenido = contenido;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the lenguaje
|
|
||||||
*/
|
|
||||||
public String getLenguaje() {
|
|
||||||
return lenguaje;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param lenguaje the lenguaje to set
|
|
||||||
*/
|
|
||||||
public void setLenguaje(String lenguaje) {
|
|
||||||
this.lenguaje = lenguaje;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
package com.manalejandro.arjion.model;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class Consulta {
|
|
||||||
private List<Documento> documentos = new ArrayList<Documento>();
|
|
||||||
private String suggest;
|
|
||||||
private List<String> autocomplete = new ArrayList<String>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the documentos
|
|
||||||
*/
|
|
||||||
public List<Documento> getDocumentos() {
|
|
||||||
return documentos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the suggest
|
|
||||||
*/
|
|
||||||
public String getSuggest() {
|
|
||||||
return suggest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the autocomplete
|
|
||||||
*/
|
|
||||||
public List<String> getAutocomplete() {
|
|
||||||
return autocomplete;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param documentos the documentos to set
|
|
||||||
*/
|
|
||||||
public void setDocumentos(List<Documento> documentos) {
|
|
||||||
this.documentos = documentos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param suggest the suggest to set
|
|
||||||
*/
|
|
||||||
public void setSuggest(String suggest) {
|
|
||||||
this.suggest = suggest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param autocomplete the autocomplete to set
|
|
||||||
*/
|
|
||||||
public void setAutocomplete(List<String> autocomplete) {
|
|
||||||
this.autocomplete = autocomplete;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,108 +1,32 @@
|
|||||||
package com.manalejandro.arjion.model;
|
package com.manalejandro.arjion.model;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
import org.springframework.data.elasticsearch.annotations.Mapping;
|
||||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
@Document(indexName = "#{@indexName}", type = "#{@documentType}")
|
@Document(indexName = "#{@indexName}", type = "#{@documentType}")
|
||||||
@Setting(settingPath = "/elasticsearch/settings.json")
|
@Setting(settingPath = "/elasticsearch/settings.json")
|
||||||
@Mapping(mappingPath = "/elasticsearch/mapping.json")
|
@Mapping(mappingPath = "/elasticsearch/mapping.json")
|
||||||
public class Documento {
|
public class Documento {
|
||||||
@Id
|
@Id
|
||||||
public String nombre;
|
public Integer id;
|
||||||
public Integer tamano;
|
|
||||||
public JsonNode metadata;
|
|
||||||
public String contenido;
|
|
||||||
public String lenguaje;
|
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public Documento(@JsonProperty("nombre") String nombre, @JsonProperty("tamano") Integer tamano,
|
public Documento(@JsonProperty("id") Integer id) {
|
||||||
@JsonProperty("metadata") JsonNode metadata, @JsonProperty("contenido") String contenido,
|
super();
|
||||||
@JsonProperty("lenguaje") String lenguaje) {
|
this.id = id;
|
||||||
this.nombre = nombre;
|
}
|
||||||
this.tamano = tamano;
|
|
||||||
this.metadata = metadata;
|
|
||||||
this.contenido = contenido;
|
|
||||||
this.lenguaje = lenguaje;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
@JsonProperty("id")
|
||||||
* @return the nombre
|
public Integer getId() {
|
||||||
*/
|
return id;
|
||||||
@JsonProperty("nombre")
|
}
|
||||||
public String getNombre() {
|
|
||||||
return nombre;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public void setId(Integer id) {
|
||||||
* @param nombre the nombre to set
|
this.id = id;
|
||||||
*/
|
}
|
||||||
public void setNombre(String nombre) {
|
|
||||||
this.nombre = nombre;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the tamano
|
|
||||||
*/
|
|
||||||
@JsonProperty("tamano")
|
|
||||||
public Integer getTamano() {
|
|
||||||
return tamano;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param tamano the tamano to set
|
|
||||||
*/
|
|
||||||
public void setTamano(Integer tamano) {
|
|
||||||
this.tamano = tamano;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the metadata
|
|
||||||
*/
|
|
||||||
@JsonProperty("metadata")
|
|
||||||
public JsonNode getMetadata() {
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param metadata the metadata to set
|
|
||||||
*/
|
|
||||||
public void setMetadata(JsonNode metadata) {
|
|
||||||
this.metadata = metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the contenido
|
|
||||||
*/
|
|
||||||
@JsonProperty("contenido")
|
|
||||||
public String getContenido() {
|
|
||||||
return contenido;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param contenido the contenido to set
|
|
||||||
*/
|
|
||||||
public void setContenido(String contenido) {
|
|
||||||
this.contenido = contenido;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the lenguaje
|
|
||||||
*/
|
|
||||||
@JsonProperty("lenguaje")
|
|
||||||
public String getLenguaje() {
|
|
||||||
return lenguaje;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param lenguaje the lenguaje to set
|
|
||||||
*/
|
|
||||||
public void setLenguaje(String lenguaje) {
|
|
||||||
this.lenguaje = lenguaje;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,8 @@
|
|||||||
package com.manalejandro.arjion.services;
|
package com.manalejandro.arjion.services;
|
||||||
|
|
||||||
import java.util.List;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.manalejandro.arjion.model.Consulta;
|
|
||||||
import com.manalejandro.arjion.model.Documento;
|
|
||||||
|
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
|
|
||||||
|
@Service
|
||||||
public interface MainService {
|
public interface MainService {
|
||||||
|
|
||||||
public boolean save(Documento doc);
|
|
||||||
|
|
||||||
public long count();
|
|
||||||
|
|
||||||
public List<Documento> findAllDocumento();
|
|
||||||
|
|
||||||
public Documento findOne(String nombre);
|
|
||||||
|
|
||||||
public Integer maxTamano();
|
|
||||||
|
|
||||||
public Consulta search(String busqueda, String[] tipo, Integer tamano, Pageable pageable);
|
|
||||||
}
|
}
|
||||||
|
@ -1,127 +1,5 @@
|
|||||||
package com.manalejandro.arjion.services;
|
package com.manalejandro.arjion.services;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.manalejandro.arjion.model.Consulta;
|
|
||||||
import com.manalejandro.arjion.model.Documento;
|
|
||||||
import com.manalejandro.arjion.repositories.MainRepository;
|
|
||||||
|
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
|
||||||
import org.elasticsearch.index.query.QueryBuilders;
|
|
||||||
import org.elasticsearch.search.aggregations.AggregationBuilder;
|
|
||||||
import org.elasticsearch.search.aggregations.AggregationBuilders;
|
|
||||||
import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry;
|
|
||||||
import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry.Option;
|
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
|
||||||
import org.elasticsearch.search.suggest.SuggestBuilders;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
import org.springframework.data.domain.Sort;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class MainServiceImpl implements MainService {
|
public class MainServiceImpl implements MainService {
|
||||||
|
|
||||||
private final ApplicationContext appContext;
|
|
||||||
private final MainRepository mainRepository;
|
|
||||||
|
|
||||||
@Value("#{@indexName}")
|
|
||||||
private String index;
|
|
||||||
@Value("#{@documentType}")
|
|
||||||
private String document;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public MainServiceImpl(MainRepository mainRepository, ApplicationContext appContext) {
|
|
||||||
this.mainRepository = mainRepository;
|
|
||||||
this.appContext = appContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean save(Documento doc) {
|
|
||||||
if (!mainRepository.existsById(doc.nombre)) {
|
|
||||||
if (mainRepository.save(doc) != null)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
} else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long count() {
|
|
||||||
return mainRepository.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Documento> findAllDocumento() {
|
|
||||||
List<Documento> docs = new ArrayList<Documento>();
|
|
||||||
mainRepository.findAll().forEach(doc -> {
|
|
||||||
docs.add((Documento) doc);
|
|
||||||
});
|
|
||||||
return docs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Documento findOne(String nombre) {
|
|
||||||
return mainRepository.findById(nombre).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer maxTamano() {
|
|
||||||
return mainRepository.findAll(new Sort(Sort.Direction.DESC, "tamano")).iterator().next().getTamano();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Consulta search(String busqueda, String[] tipo, Integer tamano, Pageable pageable) {
|
|
||||||
Client client = (Client) appContext.getBean("client");
|
|
||||||
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
|
|
||||||
if (busqueda != null && !"null".equals(busqueda) && !busqueda.isEmpty()) {
|
|
||||||
boolQueryBuilder.must(QueryBuilders.matchQuery("nombre", busqueda));
|
|
||||||
boolQueryBuilder.should(QueryBuilders.matchQuery("contenido", busqueda));
|
|
||||||
}
|
|
||||||
if (tipo != null && tipo.length > 0)
|
|
||||||
boolQueryBuilder.filter(QueryBuilders.termsQuery("tipo", tipo));
|
|
||||||
if (tamano != null && tamano >= 0)
|
|
||||||
boolQueryBuilder.must(QueryBuilders.rangeQuery("tamano").to(tamano).includeUpper(true));
|
|
||||||
AggregationBuilder aggregation = AggregationBuilders.terms("by_xarchivo").field("x_archivo").size(10000);
|
|
||||||
SuggestBuilder suggest = new SuggestBuilder()
|
|
||||||
.addSuggestion("suggest", SuggestBuilders.completionSuggestion("nombre").text(busqueda).size(10))
|
|
||||||
.addSuggestion("phrase", SuggestBuilders.phraseSuggestion("nombre").text(busqueda).size(1)
|
|
||||||
.realWordErrorLikelihood((float) 0.95).maxErrors((float) 0.5).gramSize(2));
|
|
||||||
System.out.println(boolQueryBuilder);
|
|
||||||
SearchResponse response = client.prepareSearch(index).setQuery(boolQueryBuilder).addAggregation(aggregation)
|
|
||||||
.suggest(suggest).setSize(pageable.getPageSize()).setFrom(pageable.getPageNumber()).execute()
|
|
||||||
.actionGet();
|
|
||||||
Consulta consulta = new Consulta();
|
|
||||||
consulta.setSuggest(response.getSuggest().getSuggestion("phrase").getEntries().get(0).getOptions().size() > 0
|
|
||||||
? response.getSuggest().getSuggestion("phrase").getEntries().get(0).getOptions().get(0).getText()
|
|
||||||
.string()
|
|
||||||
: "");
|
|
||||||
for (Entry<? extends Option> entry : response.getSuggest().getSuggestion("suggest").getEntries()) {
|
|
||||||
entry.getOptions().forEach(option -> {
|
|
||||||
String suggestText = option.getText().string().trim(),
|
|
||||||
autocompleteClean = busqueda.replaceAll("[^\\p{Alnum}\\p{IsAlphabetic} ]", "");
|
|
||||||
for (String item : autocompleteClean.split(" ")) {
|
|
||||||
if (item.length() > 0) {
|
|
||||||
consulta.getAutocomplete().add(
|
|
||||||
suggestText.replaceAll("(?i)((?!<)" + item + "(?![^<>]*>))", "<strong>$1</strong>"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
try {
|
|
||||||
consulta.setDocumentos(mapper.readValue(response.getHits().getHits().toString(), List.class));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return consulta;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
package com.manalejandro.arjion.vo;
|
|
||||||
|
|
||||||
import com.manalejandro.arjion.model.Archivo;
|
|
||||||
|
|
||||||
public class DetailVO {
|
|
||||||
|
|
||||||
private Archivo archivo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the archivo
|
|
||||||
*/
|
|
||||||
public Archivo getArchivo() {
|
|
||||||
return archivo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param archivo the archivo to set
|
|
||||||
*/
|
|
||||||
public void setArchivo(Archivo archivo) {
|
|
||||||
this.archivo = archivo;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +1,5 @@
|
|||||||
package com.manalejandro.arjion.vo;
|
package com.manalejandro.arjion.vo;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.manalejandro.arjion.model.Archivo;
|
|
||||||
import com.manalejandro.arjion.model.Documento;
|
|
||||||
|
|
||||||
public class DocumentoVO {
|
public class DocumentoVO {
|
||||||
|
|
||||||
private List<Archivo> archivos = new ArrayList<Archivo>();
|
|
||||||
private long count;
|
|
||||||
private List<Documento> documentos = new ArrayList<Documento>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the archivos
|
|
||||||
*/
|
|
||||||
public List<Archivo> getArchivos() {
|
|
||||||
return archivos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param archivos the archivos to set
|
|
||||||
*/
|
|
||||||
public void setArchivos(List<Archivo> archivos) {
|
|
||||||
this.archivos = archivos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCount() {
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCount(long count) {
|
|
||||||
this.count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the documentos
|
|
||||||
*/
|
|
||||||
public List<Documento> getDocumentos() {
|
|
||||||
return documentos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param documentos the documentos to set
|
|
||||||
*/
|
|
||||||
public void setDocumentos(List<Documento> documentos) {
|
|
||||||
this.documentos = documentos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,8 @@ elasticsearch.port=9300
|
|||||||
elasticsearch.nodename=arjion
|
elasticsearch.nodename=arjion
|
||||||
arjion.indexName=documentos
|
arjion.indexName=documentos
|
||||||
arjion.documentType=documento
|
arjion.documentType=documento
|
||||||
arjion.uploadpath=/upload/
|
|
||||||
arjion.tesseractpath=/usr/bin
|
|
||||||
arjion.tesseractdatapath=/usr/share/tesseract-ocr
|
|
||||||
spring.main.allow-bean-definition-overriding=true
|
spring.main.allow-bean-definition-overriding=true
|
||||||
spring.thymeleaf.enabled=true
|
spring.thymeleaf.enabled=true
|
||||||
spring.thymeleaf.prefix=classpath:/templates/
|
spring.thymeleaf.prefix=classpath:/templates/
|
||||||
spring.thymeleaf.suffix=.html
|
spring.thymeleaf.suffix=.html
|
||||||
spring.thymeleaf.cache=false
|
spring.thymeleaf.cache=false
|
||||||
spring.servlet.multipart.max-file-size=20MB
|
|
||||||
spring.servlet.multipart.max-request-size=100MB
|
|
@ -1,38 +1,16 @@
|
|||||||
{
|
{
|
||||||
"documento": {
|
"documento": {
|
||||||
"dynamic_templates": [
|
"properties": {
|
||||||
{
|
"@timestamp": {
|
||||||
"metadata_as_keywords": {
|
"type": "date",
|
||||||
"path_match": "metadata.*",
|
"format": "strict_date_optional_time||epoch_millis"
|
||||||
"mapping": {
|
},
|
||||||
"type": "keyword"
|
"@version": {
|
||||||
}
|
"type": "keyword"
|
||||||
}
|
},
|
||||||
}
|
"id": {
|
||||||
],
|
"type": "long"
|
||||||
"properties": {
|
}
|
||||||
"@timestamp": {
|
}
|
||||||
"type": "date",
|
}
|
||||||
"format": "strict_date_optional_time||epoch_millis"
|
|
||||||
},
|
|
||||||
"@version": {
|
|
||||||
"type": "keyword"
|
|
||||||
},
|
|
||||||
"nombre": {
|
|
||||||
"type": "text"
|
|
||||||
},
|
|
||||||
"tamano": {
|
|
||||||
"type": "long"
|
|
||||||
},
|
|
||||||
"metadata": {
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"contenido": {
|
|
||||||
"type": "text"
|
|
||||||
},
|
|
||||||
"lenguaje": {
|
|
||||||
"type": "keyword"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,4 +0,0 @@
|
|||||||
hr {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Arjion</title>
|
|
||||||
<link rel="stylesheet" th:href="@{/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css}">
|
|
||||||
<link rel="stylesheet" th:href="@{/css/main.css}">
|
|
||||||
<script th:src="@{/webjars/jquery/3.1.1-1/jquery.min.js}"></script>
|
|
||||||
<script th:src="@{/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js}"></script>
|
|
||||||
<script th:src="@{/js/main.js}"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<header class="text-center">
|
|
||||||
<a th:href="@{/}">
|
|
||||||
<h1 class="text-primary">Arjion</h1>
|
|
||||||
</a>
|
|
||||||
<h3 class="text-warning">[[${detailVO.archivo.nombre}]]</h3>
|
|
||||||
</header>
|
|
||||||
<section class="col-md-12">
|
|
||||||
<hr>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<span class="col-md-1 text-muted">Tamaño</span>
|
|
||||||
<span class="col-md-11 text-muted">[[${detailVO.archivo.tamano}]] bytes</span>
|
|
||||||
<span class="col-md-1 text-muted">Lenguaje</span>
|
|
||||||
<span class="col-md-11 text-muted">[[${detailVO.archivo.lenguaje}]]</span>
|
|
||||||
<span class="col-md-1 text-success">Metadatos</span>
|
|
||||||
<span class="col-md-11 text-success"><ul><li th:each="meta : ${detailVO.archivo.metadata}"><span th:text="${meta.key}"></span>: <span th:text="${meta.value}"></span></li></ul></span>
|
|
||||||
<span class="col-md-1 text-warning">Contenido</span>
|
|
||||||
<pre class="col-md-11 text-warning">[[${detailVO.archivo.contenido}]]</pre>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="col-md-12">
|
|
||||||
<hr>
|
|
||||||
</section>
|
|
||||||
<footer class="col-md-12 text-center">
|
|
||||||
<span class="col-md-12">
|
|
||||||
<a class="btn btn-primary" th:href="@{/}">Volver</a>
|
|
||||||
</span>
|
|
||||||
<span>2018</span>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -1,17 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Error</title>
|
<title>Error</title>
|
||||||
<link rel="stylesheet" th:href="@{/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css}">
|
|
||||||
<script th:src="@{/webjars/jquery/3.1.1-1/jquery.min.js}"></script>
|
|
||||||
<script th:src="@{/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js}"></script>
|
|
||||||
</head>
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
<body class="text-center text-danger">
|
|
||||||
<h2>Error</h2>
|
|
||||||
<button class="btn btn-primary" th:onclick="'window.location.pathname=\'' + @{/} + '\''">Volver</button>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -1,18 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Error</title>
|
|
||||||
<link rel="stylesheet" th:href="@{/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css}">
|
|
||||||
<script th:src="@{/webjars/jquery/3.1.1-1/jquery.min.js}"></script>
|
|
||||||
<script th:src="@{/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js}"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="text-center text-danger">
|
|
||||||
<h2>Error</h2>
|
|
||||||
<h4>El archivo ya existe o hubo un error</h4>
|
|
||||||
<button class="btn btn-primary" th:onclick="'window.location.pathname=\'' + @{/} + '\''">Volver</button>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -1,84 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Arjion</title>
|
<title>Arjion</title>
|
||||||
<link rel="stylesheet" th:href="@{/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css}">
|
<link rel="stylesheet" href="webjars/bootstrap/3.3.7-1/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" th:href="@{/css/main.css}">
|
<script src="webjars/jquery/3.1.1-1/jquery.min.js"></script>
|
||||||
<script th:src="@{/webjars/jquery/3.1.1-1/jquery.min.js}"></script>
|
<script src="webjars/bootstrap/3.3.7-1/js/bootstrap.min.js"></script>
|
||||||
<script th:src="@{/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js}"></script>
|
|
||||||
<script th:src="@{/js/main.js}"></script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header class="text-center">
|
|
||||||
<a th:href="@{/}">
|
|
||||||
<h1 class="text-primary">Arjion</h1>
|
|
||||||
</a>
|
|
||||||
<h3 class="text-warning">[[${documentoVO.count}]] archivos</h3>
|
|
||||||
</header>
|
|
||||||
<section class="text-center col-md-4 col-md-offset-4">
|
|
||||||
<form class="form-horizontal form-label-left" method="post" enctype="multipart/form-data" novalidate="novalidate" th:action="@{/upload}"
|
|
||||||
th:object="${documentForm}">
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-addon">
|
|
||||||
<span class="glyphicon glyphicon-file"></span>
|
|
||||||
</span>
|
|
||||||
<label class="input-group-addon custom-file">
|
|
||||||
<input type="file" name="archivos" class="custom-file-input" multiple="multiple" />
|
|
||||||
<span class="custom-file-control"></span>
|
|
||||||
</label>
|
|
||||||
<span class="input-group-addon">
|
|
||||||
<button class="btn btn-primary" type="submit">
|
|
||||||
<span class="glyphicon glyphicon-level-up"></span>
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
<section class="col-md-12">
|
|
||||||
<hr>
|
|
||||||
</section>
|
|
||||||
<section class="col-md-12">
|
|
||||||
<div th:each="arc : ${documentoVO.archivos}" class="col-md-12">
|
|
||||||
<span class="col-md-1 text-primary lead">Nombre</span>
|
|
||||||
<span class="col-md-11 text-primary lead">[[${arc.nombre}]]</span>
|
|
||||||
<span class="col-md-1 text-muted">Tamaño</span>
|
|
||||||
<span class="col-md-11 text-muted">[[${arc.tamano}]] bytes</span>
|
|
||||||
<span class="col-md-1 text-muted">Lenguaje</span>
|
|
||||||
<span class="col-md-11 text-muted">[[${arc.lenguaje}]]</span>
|
|
||||||
<span class="col-md-1 text-success">Metadatos</span>
|
|
||||||
<span class="col-md-11 text-success"><ul><li th:each="meta : ${arc.metadata}"><span th:text="${meta.key}"></span>: <span th:text="${meta.value}"></span></li></ul></span>
|
|
||||||
<span class="col-md-1 text-warning">Contenido</span>
|
|
||||||
<pre class="col-md-11 text-warning">[[${arc.contenido}]]</pre>
|
|
||||||
<span class="col-md-12">
|
|
||||||
<hr>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="col-md-12">
|
|
||||||
<hr>
|
|
||||||
</section>
|
|
||||||
<section class="col-md-12 text-center">
|
|
||||||
<div th:each="doc : ${documentoVO.documentos}">
|
|
||||||
<div>
|
|
||||||
<span class="col-md-12 text-primary">
|
|
||||||
<a th:href="@{'/detail'(nombre=${doc.nombre})}" class="lead">[[${doc.nombre}]]</a> -
|
|
||||||
<a th:href="@{'/download'(filename=${doc.nombre})}">download</a>
|
|
||||||
<br>[[${doc.tamano}]] bytes
|
|
||||||
<br>[[${doc.lenguaje}]]</span>
|
|
||||||
<span class="col-md-12 text-success">[[${#strings.abbreviate(doc.metadata,200)}]]</span>
|
|
||||||
<span class="col-md-12 text-warning">[[${#strings.abbreviate(doc.contenido,200)}]]</span>
|
|
||||||
</div>
|
|
||||||
<span class="col-md-12">
|
|
||||||
<hr>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<footer class="col-md-12 text-center">
|
|
||||||
<span>2018</span>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
x
Reference in New Issue
Block a user