Commit 0255626f by Jan Hrabal

simple boot

parent d49799fa
......@@ -5,13 +5,13 @@
<groupId>com.jh</groupId>
<artifactId>jh-boot</artifactId>
<version>0.0.2</version>
<version>0.0.3</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<version>2.2.6.RELEASE</version>
<relativePath />
</parent>
......@@ -31,10 +31,12 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
......@@ -45,51 +47,25 @@
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.4.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- <dependency> -->
<!-- <groupId>org.springframework.security.oauth.boot</groupId> -->
<!-- <artifactId>spring-security-oauth2-autoconfigure</artifactId> -->
<!-- <version>2.2.5.RELEASE</version> -->
<!-- </dependency> -->
<!-- <dependency> -->
<!-- <groupId>org.springframework.security.oauth</groupId> -->
<!-- <artifactId>spring-security-oauth2</artifactId> -->
<!-- <version>2.4.0.RELEASE</version> -->
<!-- </dependency> -->
<!-- handlebars -->
<dependency>
<groupId>com.github.jknack</groupId>
......@@ -102,13 +78,6 @@
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<!-- testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
......
package com.jh.boot;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import com.jh.boot.security.utils.TemplateEmailAuthServiceListener;
import com.jh.boot.template.HibernateLoaderTemplateService;
import com.jh.boot.template.HibernateTemplateLoader;
import com.jh.boot.template.TemplateEngine;
import com.jh.boot.template.TemplateLoader;
import com.jh.boot.template.TemplateService;
import com.jh.boot.template.TemplateValuesConfig;
import com.jh.boot.template.handlebars.HandlebarsTemplateEngine;
public class JhBootApplication {
// @Bean
// @ConditionalOnProperty(value = "email.local.enabled", havingValue = "true", matchIfMissing = true)
// public LocalEmailService emailService() {
// return new LocalEmailService();
// }
@Bean
@ConditionalOnProperty(value = "auth.listener.email.enabled", havingValue = "true", matchIfMissing = false)
public TemplateEmailAuthServiceListener authServiceListener() {
return new TemplateEmailAuthServiceListener();
}
@Bean
@ConditionalOnMissingBean(TemplateEngine.class)
public TemplateEngine templateEngine() {
return new HandlebarsTemplateEngine();
}
@Bean
@ConditionalOnMissingBean(TemplateLoader.class)
public TemplateLoader templateLoader() {
return new HibernateTemplateLoader();
}
@Bean
@ConditionalOnMissingBean(TemplateService.class)
public TemplateService templateService() {
return new HibernateLoaderTemplateService();
}
@Bean
public TemplateValuesConfig templateValuesConfig() {
return new TemplateValuesConfig();
}
}
package com.jh.boot.attachment;
import java.io.InputStream;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class AbstractHibernateAttachmentService implements AttachmentService {
private AttachmentRepository repository;
@Override
public Attachment saveAttachment(Attachment attachment, InputStream content) {
saveAttachment(attachment);
saveData(attachment, content);
return attachment;
}
protected abstract void saveData(Attachment attachment, InputStream stream);
@Override
public Attachment saveAttachment(Attachment attachment) {
repository.save(attachment);
return attachment;
}
@Override
public List<Attachment> fetchAttachments(Long unitId, String objectType, Long objectId) {
return repository.findForUnitIdAndObject(unitId, objectType, objectId);
}
@Override
public Attachment fetchAttachment(Long attachmentId) {
return repository.findById(attachmentId);
}
@Override
public void deleteAttachment(Long attachmentId) {
Attachment a = repository.findById(attachmentId);
if (a != null) {
repository.delete(a);
deleteData(a);
}
}
protected abstract void deleteData(Attachment attachment);
@Autowired(required = false)
public void setRepository(AttachmentRepository repository) {
this.repository = repository;
}
}
package com.jh.boot.attachment;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import com.jh.boot.jpa.AbstractIdEntity;
/**
* The Class Attachment.
*/
@Entity
@Table(name = "ATTACHMENT")
public class Attachment extends AbstractIdEntity {
/** The unit id. */
@Column(name = "UNIT_ID")
private Long unitId;
/** The object type. */
@Column(name = "OBJECT_TYPE")
private String objectType;
/** The object id. */
@Column(name = "OBJECT_ID")
private Long objectId;
/** The name. */
private String name;
/** The mime type. */
@Column(name = "MIME_TYPE")
private String mimeType;
/** The size. */
@Column(name = "SIZE")
private Long size;
/** The filename. */
@Column(name = "FILENAME")
private String filename;
/** The uploaded. */
@Column(name = "UPLOADED")
private Date uploaded;
/**
* Gets the unit id.
*
* @return the unit id
*/
public Long getUnitId() {
return unitId;
}
/**
* Sets the unit id.
*
* @param unitId the new unit id
*/
public void setUnitId(Long unitId) {
this.unitId = unitId;
}
/**
* Gets the object type.
*
* @return the object type
*/
public String getObjectType() {
return objectType;
}
/**
* Sets the object type.
*
* @param objectType the new object type
*/
public void setObjectType(String objectType) {
this.objectType = objectType;
}
/**
* Gets the object id.
*
* @return the object id
*/
public Long getObjectId() {
return objectId;
}
/**
* Sets the object id.
*
* @param objectId the new object id
*/
public void setObjectId(Long objectId) {
this.objectId = objectId;
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Sets the name.
*
* @param name the new name
*/
public void setName(String name) {
this.name = name;
}
/**
* Gets the mime type.
*
* @return the mime type
*/
public String getMimeType() {
return mimeType;
}
/**
* Sets the mime type.
*
* @param mimeType the new mime type
*/
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
/**
* Gets the size.
*
* @return the size
*/
public Long getSize() {
return size;
}
/**
* Sets the size.
*
* @param size the new size
*/
public void setSize(Long size) {
this.size = size;
}
/**
* Gets the filename.
*
* @return the filename
*/
public String getFilename() {
return filename;
}
/**
* Sets the filename.
*
* @param filename the new filename
*/
public void setFilename(String filename) {
this.filename = filename;
}
/**
* Gets the uploaded.
*
* @return the uploaded
*/
public Date getUploaded() {
return uploaded;
}
/**
* Sets the uploaded.
*
* @param uploaded the new uploaded
*/
public void setUploaded(Date uploaded) {
this.uploaded = uploaded;
}
}
package com.jh.boot.attachment;
import java.util.List;
import javax.persistence.TypedQuery;
import org.springframework.stereotype.Repository;
import com.jh.boot.jpa.AbstractHibernateRepository;
import com.jh.boot.web.list.Page;
import com.jh.boot.web.list.PagingInfo;
/**
* The Class AttachmentRepository.
*/
@Repository
public class AttachmentRepository extends AbstractHibernateRepository {
/**
* Find for unit id and object.
*
* @param unitId the unit id
* @param objectType the object type
* @param objectId the object id
* @param paging the paging
* @return the page
*/
public Page<Attachment> findForUnitIdAndObject(Long unitId, String objectType, Long objectId, PagingInfo paging) {
TypedQuery<Attachment> query = getListQuery(unitId, objectType, objectId);
query.setFirstResult(paging.getPage() * paging.getPageSize());
query.setMaxResults(paging.getPageSize());
//return new Page<>(0, 0, 0, 0, null, objectType, null);
//FIXME
return Page.empty();
}
/**
* Find for unit id and object.
*
* @param unitId the unit id
* @param objectType the object type
* @param objectId the object id
* @return the list
*/
public List<Attachment> findForUnitIdAndObject(Long unitId, String objectType, Long objectId) {
TypedQuery<Attachment> query = getListQuery(unitId, objectType, objectId);
return query.getResultList();
}
protected TypedQuery<Attachment> getListQuery(Long unitId, String objectType, Long objectId) {
String hql = "select a from Attachment a";
if (unitId != null || objectType != null || objectId != null) {
hql += " where ";
if (unitId != null) {
hql += " a.unitId = :unitId";
}
if (objectType != null) {
hql += " a.objectType = :objectType";
}
if (objectId != null) {
hql += " a.objectId = :objectId";
}
}
TypedQuery<Attachment> query = entityManager.createQuery(hql, Attachment.class);
if (unitId != null) {
query.setParameter("unitId", unitId);
}
if (objectType != null) {
query.setParameter("objectType", objectType);
}
if (objectId != null) {
query.setParameter("objectId", objectId);
}
return query;
}
/**
* Rename.
*
* @param unitId the unit id
* @param objectType the object type
* @param objectId the object id
* @param attachmentId the attachment id
* @param name the name
*/
public void rename(Long attachmentId, String name) {
Attachment a = findById(attachmentId);
a.setName(name);
}
public Attachment findById(Long id) {
return entityManager.find(Attachment.class, id);
}
}
package com.jh.boot.attachment;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.springframework.web.multipart.MultipartFile;
public interface AttachmentService {
Attachment saveAttachment(Attachment attachment, InputStream content);
Attachment saveAttachment(Attachment attachment);
List<Attachment> fetchAttachments(Long unitId, String objectType, Long objectId);
Attachment fetchAttachment(Long attachmentId);
InputStream fetchAttachmentBody(Attachment attachment);
void deleteAttachment(Long attachmentId);
// default methods
public default Attachment addAttachment(String objectType, Long objectId, MultipartFile file) {
return addAttachment(null, objectType, objectId, file);
}
public default Attachment addAttachment(Long unitId, String objectType, Long objectId, MultipartFile file) {
Attachment a = new Attachment();
a.setFilename(file.getOriginalFilename());
a.setSize(file.getSize());
a.setObjectId(objectId);
a.setObjectType(objectType);
try {
saveAttachment(a, file.getInputStream());
} catch (Exception e) {
throw new RuntimeException("Cannot upload attachment", e);
}
return a;
}
public default Attachment syncAttachment(String objectType, Long objectId, Attachment currentAttachment, Attachment newAttachment, MultipartFile file) {
return syncAttachment(null, objectType, objectId, currentAttachment, newAttachment, file);
}
public default Attachment syncAttachment(Long unitId, String objectType, Long objectId, Attachment currentAttachment, Attachment newAttachment, MultipartFile file) {
Attachment a = null;
if (currentAttachment != null && newAttachment == null) {
//delete current attachment
deleteAttachment(currentAttachment.getId());
}
if (file != null) {
a = addAttachment(unitId, objectType, objectId, file);
} else {
a = currentAttachment;
}
return a;
}
public default <C extends Collection<Attachment>> C syncAttachments(String objectType, Long objectId, C currentAttachments, C newAttachments, MultipartFile[] files, Class<C> clazz) {
return syncAttachments(null, objectType, objectId, currentAttachments, newAttachments, files, clazz);
}
public default <C extends Collection<Attachment>> C syncAttachments(Long unitId, String objectType, Long objectId, C currentAttachments, C newAttachments, MultipartFile[] files, Class<C> clazz) {
//decide whether Set or List
if (currentAttachments == null) {
if (Set.class.isAssignableFrom(clazz)) {
currentAttachments = (C) new HashSet<Attachment>();
} else if (List.class.isAssignableFrom(clazz)) {
currentAttachments = (C) new ArrayList<Attachment>();
} else {
throw new IllegalArgumentException("Invalid collection type");
}
}
if (newAttachments == null || newAttachments.isEmpty()) {
currentAttachments.clear();
} else {
Iterator<Attachment> it = currentAttachments.iterator();
while (it.hasNext()) {
Attachment a = it.next();
if (!newAttachments.contains(a)) {
it.remove();
}
}
}
//TODO add attachments?
if (files != null && files.length > 0) {
for (MultipartFile f : files) {
currentAttachments.add(addAttachment(unitId, objectType, objectId, f));
}
}
return currentAttachments;
}
}
package com.jh.boot.attachment;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.Objects;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Value;
public class FileBasedAttachmentService extends AbstractHibernateAttachmentService {
private String dataDirectory;
@Override
public InputStream fetchAttachmentBody(Attachment attachment) {
try {
return new FileInputStream(file(attachment));
} catch (FileNotFoundException e) {
throw new RuntimeException("File not found", e);
}
}
@Override
protected void saveData(Attachment attachment, InputStream stream) {
try (FileOutputStream fos = new FileOutputStream(file(attachment))) {
IOUtils.copy(stream, fos);
} catch (Exception e) {
throw new RuntimeException("Cannot write data", e);
}
}
@Override
protected void deleteData(Attachment attachment) {
File file = file(attachment);
if (file.exists()) {
file.delete();
file = file.getParentFile();
if (file.listFiles().length == 0) {
//delete ?
file.delete();
}
}
}
protected File file(Attachment attachment) {
Objects.requireNonNull(attachment, "Attachment must not be null");
File file = Paths.get(dataDirectory, s(attachment.getUnitId()), attachment.getObjectType(), s(attachment.getObjectId()), attachment.getFilename()).toFile();
file.getParentFile().mkdirs();
return file;
}
protected String s(Number n) {
return n == null ? "0" : String.valueOf(n);
}
@Value("${attachment.store.path:/var/data}")
public void setDataDirectory(String dataDirectory) {
this.dataDirectory = dataDirectory;
}
}
package com.jh.boot.attachment.api;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.io.InputStreamResource;
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;
import com.jh.boot.attachment.Attachment;
import com.jh.boot.attachment.AttachmentService;
@Controller
@ConditionalOnProperty(value = "attachments.api.enabled", havingValue = "true", matchIfMissing = true)
public class AttachmentApiController {
@Autowired
private AttachmentService service;
@Autowired
private AttachmentContentProvider contentProvider;
@GetMapping("/attachments/{unitId}/{objectType}/{objectId}")
public @ResponseBody List<Attachment> listAttachments(@PathVariable("unitId") Long unitId, @PathVariable("objectType") String objectType, @PathVariable("objectId") Long objectId) {
return service.fetchAttachments(unitId, objectType, objectId);
}
@GetMapping("/attachments/{attachmentId}/data")
public ResponseEntity<InputStreamResource> fetch(@PathVariable("attachmentId") Long attachmentId) {
return contentProvider.fetch(attachmentId);
}
}
package com.jh.boot.attachment.api;
import java.io.InputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.jh.boot.attachment.Attachment;
import com.jh.boot.attachment.AttachmentService;
import com.jh.boot.web.error.NotFoundException;
@Component
public class AttachmentContentProvider {
private AttachmentService service;
public ResponseEntity<InputStreamResource> fetch(Long attachmentId) {
Attachment a = service.fetchAttachment(attachmentId);
if (a == null) {
throw new NotFoundException();
}
InputStream is = service.fetchAttachmentBody(a);
if (is == null) {
throw new NotFoundException();
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(StringUtils.hasText(a.getMimeType()) ? MediaType.parseMediaType(a.getMimeType()) : MediaType.APPLICATION_OCTET_STREAM);
headers.set("Content-Disposition", "attachment; filename=\"" + a.getFilename() + "\"");
return new ResponseEntity<>(new InputStreamResource(is), headers, HttpStatus.OK);
}
@Autowired(required = false)
public void setService(AttachmentService service) {
this.service = service;
}
}
package com.jh.boot.document;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import com.jh.boot.jpa.AbstractIdEntity;
@Entity
@Table(name = "LEGAL_DOCUMENT")
public class LegalDocument extends AbstractIdEntity {
private static final long serialVersionUID = 1L;
@Column(name = "CODE")
private String code;
@Column(name = "LOCALE")
private String locale;
@Column(name = "CONTENT")
private String content;
public LegalDocument() {
}
public LegalDocument(String code, String locale, String text) {
super();
this.code = code;
this.locale = locale;
this.content = text;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public String getContent() {
return content;
}
public void setContent(String text) {
this.content = text;
}
}
package com.jh.boot.document;
import javax.persistence.Query;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import com.jh.boot.jpa.AbstractHibernateRepository;
@Repository
public class LegalDocumentRepository extends AbstractHibernateRepository {
public LegalDocument findByCodeAndLocale(String code, String locale) {
if (code == null) {
return null;
}
if (!StringUtils.hasText(locale)) {
locale = "en";
}
locale = locale.replace("-", "_");
Query q = entityManager.createQuery("select ld from LegalDocument ld where lower(ld.code) = :code and lower(ld.locale) = :locale");
q.setParameter("code", code.toLowerCase());
q.setParameter("locale", locale.toLowerCase());
LegalDocument ld = singleResult(q);
if (ld == null) {
if (locale.indexOf('_') > -1) {
return findByCodeAndLocale(code, locale.substring(0, locale.lastIndexOf('_')));
} else if (!"en".equalsIgnoreCase(locale)) {
return findByCodeAndLocale(code, "en");
}
}
return ld;
}
}
package com.jh.boot.document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class LegalDocumentService {
@Autowired
private LegalDocumentRepository repo;
@Transactional
public LegalDocument findByCodeAndLocale(String code, String locale) {
return repo.findByCodeAndLocale(code, locale);
}
}
package com.jh.boot.domain;
public enum DateType {
BILLED_DATE("billedDate"),
DUE_DATE("dueDate");
private String column;
private DateType(String dateType) {
this.column = dateType;
}
public String getColumn() {
return column;
}
}
package com.jh.boot.domain;
public class NamedValue<T> {
/** The name. */
private String name;
/** The value. */
private T value;
/** The id. */
private Long id;
/**
* Instantiates a new named value.
*
* @param name the name
* @param value the value
*/
public NamedValue(String name, T value) {
super();
this.name = name;
this.value = value;
}
/**
* Instantiates a new named value.
*
* @param id the id
* @param name the name
* @param value the value
*/
public NamedValue(Long id, String name, T value) {
super();
this.id = id;
this.name = name;
this.value = value;
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Gets the value.
*
* @return the value
*/
public T getValue() {
return value;
}
/**
* Gets the id.
*
* @return the id
*/
public Long getId() {
return id;
}
}
\ No newline at end of file
package com.jh.boot.email;
import java.util.Set;
/**
* The Class Email.
*/
public class Email {
/** The locked. */
private Boolean locked;
/** The email from. */
private String emailFrom;
/** The recipients. */
private Set<EmailRecipient> recipients;
/** The subject. */
private String subject;
/** The text. */
private String text;
/** The html. */
private String html;
/** The to be sent. */
private Boolean toBeSent;
/** The status. */
private String status;
/** The error. */
private String error;
/** The receipt. */
private Boolean receipt;
/** The attachments. */
private Set<EmailAttachment> attachments;
/**
* Gets the locked.
*
* @return the locked
*/
public Boolean getLocked() {
return locked;
}
/**
* Sets the locked.
*
* @param locked the new locked
*/
public void setLocked(Boolean locked) {
this.locked = locked;
}
/**
* Gets the from.
*
* @return the from
*/
public String getFrom() {
return emailFrom;
}
/**
* Sets the from.
*
* @param from the new from
*/
public void setFrom(String from) {
this.emailFrom = from;
}
/**
* Gets the recipients.
*
* @return the recipients
*/
public Set<EmailRecipient> getRecipients() {
return recipients;
}
/**
* Sets the recipients.
*
* @param recipients the new recipients
*/
public void setRecipients(Set<EmailRecipient> recipients) {
this.recipients = recipients;
}
/**
* Gets the subject.
*
* @return the subject
*/
public String getSubject() {
return subject;
}
/**
* Sets the subject.
*
* @param subject the new subject
*/
public void setSubject(String subject) {
this.subject = subject;
}
/**
* Gets the text.
*
* @return the text
*/
public String getText() {
return text;
}
/**
* Sets the text.
*
* @param text the new text
*/
public void setText(String text) {
this.text = text;
}
/**
* Gets the html.
*
* @return the html
*/
public String getHtml() {
return html;
}
/**
* Sets the html.
*
* @param html the new html
*/
public void setHtml(String html) {
this.html = html;
}
/**
* Gets the status.
*
* @return the status
*/
public String getStatus() {
return status;
}
/**
* Sets the status.
*
* @param status the new status
*/
public void setStatus(String status) {
this.status = status;
}
/**
* Gets the attachments.
*
* @return the attachments
*/
public Set<EmailAttachment> getAttachments() {
return attachments;
}
/**
* Sets the attachments.
*
* @param attachments the new attachments
*/
public void setAttachments(Set<EmailAttachment> attachments) {
this.attachments = attachments;
}
/**
* Gets the to be sent.
*
* @return the to be sent
*/
public Boolean getToBeSent() {
return toBeSent;
}
/**
* Sets the to be sent.
*
* @param toBeSent the new to be sent
*/
public void setToBeSent(Boolean toBeSent) {
this.toBeSent = toBeSent;
}
/**
* Gets the email from.
*
* @return the email from
*/
public String getEmailFrom() {
return emailFrom;
}
/**
* Sets the email from.
*
* @param emailFrom the new email from
*/
public void setEmailFrom(String emailFrom) {
this.emailFrom = emailFrom;
}
/**
* Gets the error.
*
* @return the error
*/
public String getError() {
return error;
}
/**
* Sets the error.
*
* @param error the new error
*/
public void setError(String error) {
this.error = error;
}
/**
* Gets the receipt.
*
* @return the receipt
*/
public Boolean getReceipt() {
return receipt;
}
/**
* Sets the receipt.
*
* @param receipt the new receipt
*/
public void setReceipt(Boolean receipt) {
this.receipt = receipt;
}
}
/*
* Created on 8. 8. 2017 8:36:15
*
*/
package com.jh.boot.email;
import java.util.Base64;
import java.util.Base64.Encoder;
/**
* The Class EmailAttachment.
*
* @author Jan Hrabal
*/
public class EmailAttachment {
/** The name. */
private String name;
/** The mime type. */
private String mimeType;
/** The data. */
//base 64
private String data;
/** The cid. */
private String cid;
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Sets the name.
*
* @param name the new name
*/
public void setName(String name) {
this.name = name;
}
/**
* Gets the mime type.
*
* @return the mime type
*/
public String getMimeType() {
return mimeType;
}
/**
* Sets the mime type.
*
* @param mimeType the new mime type
*/
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
/**
* Gets the data.
*
* @return the data
*/
public String getData() {
return data;
}
/**
* Sets the data.
*
* @param data the new data
*/
public void setData(String data) {
this.data = data;
}
/**
* Sets the data.
*
* @param bytes the new data
*/
public void setData(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
setData((String) null);
return;
}
Encoder encoder = Base64.getEncoder();
setData(new String(encoder.encode(bytes)));
}
/**
* Gets the cid.
*
* @return the cid
*/
public String getCid() {
return cid;
}
/**
* Sets the cid.
*
* @param cid the new cid
*/
public void setCid(String cid) {
this.cid = cid;
}
}
package com.jh.boot.email;
/**
* The Class EmailRecipient.
*/
public class EmailRecipient {
/** The address. */
private String address;
/** The recipient type. */
private RecipientType recipientType;
/**
* Instantiates a new email recipient.
*/
public EmailRecipient() {
}
/**
* Instantiates a new email recipient.
*
* @param address the address
* @param recipientType the recipient type
*/
public EmailRecipient(String address, RecipientType recipientType) {
this.address = address;
this.recipientType = recipientType;
}
/**
* Gets the address.
*
* @return the address
*/
public String getAddress() {
return address;
}
/**
* Sets the address.
*
* @param address the new address
*/
public void setAddress(String address) {
this.address = address;
}
/**
* Gets the recipient type.
*
* @return the recipient type
*/
public RecipientType getRecipientType() {
return recipientType;
}
/**
* Sets the recipient type.
*
* @param recipientType the new recipient type
*/
public void setRecipientType(RecipientType recipientType) {
this.recipientType = recipientType;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + ((recipientType == null) ? 0 : recipientType.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof EmailRecipient)) {
return false;
}
EmailRecipient other = (EmailRecipient) obj;
if (address == null) {
if (other.address != null) {
return false;
}
} else if (!address.equals(other.address)) {
return false;
}
if (recipientType != other.recipientType) {
return false;
}
return true;
}
}
package com.jh.boot.email;
/**
* The Interface EmailService.
*/
public interface EmailService {
/**
* Send email.
*
* @param email the email
* @return the email
*/
Email sendEmail(Email email);
}
\ No newline at end of file
package com.jh.boot.email;
/**
* The Enum RecipientType.
*/
public enum RecipientType {
/** The to. */
TO,
/** The cc. */
CC,
/** The bcc. */
BCC
}
package com.jh.boot.email;
import java.net.URI;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
/**
* The Class RestEmailService.
*/
@SuppressWarnings("unused")
public class RestEmailService implements EmailService {
/** The rest template. */
protected RestTemplate restTemplate;
/** The username. */
private String username;
/** The password. */
private String password;
/** The unit id. */
private String unitId;
/** The url. */
private String url;
/** The uri. */
private URI uri;
/**
* Inits the.
*
* @throws Exception the exception
*/
@PostConstruct
public void init() throws Exception {
uri = new URI(url);
}
/**
* {@inheritDoc}
* @see com.jh.module.email.EmailService#sendEmail(com.jh.emailer.model.email.Email)
*/
@Override
public Email sendEmail(Email email) {
//TODO
RequestEntity<Email> request = new RequestEntity<>(email, HttpMethod.POST, uri);
ResponseEntity<Email> response = restTemplate.exchange(request, Email.class);
return email;
}
/**
* Sets the rest template.
*
* @param restTemplate the new rest template
*/
@Autowired
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
/**
* Sets the username.
*
* @param username the new username
*/
@Value("${email.username:}")
public void setUsername(String username) {
this.username = username;
}
/**
* Sets the password.
*
* @param password the new password
*/
@Value("${email.password:}")
public void setPassword(String password) {
this.password = password;
}
/**
* Sets the unit id.
*
* @param unitId the new unit id
*/
@Value("${email.unitId:}")
public void setUnitId(String unitId) {
this.unitId = unitId;
}
/**
* Sets the url.
*
* @param url the new url
*/
@Value("${email.url:}")
public void setUrl(String url) {
this.url = url;
}
}
/*
'use strict';
const http = require('http');
//TODO
module.exports = function(config = {}) {
//TODO validate config
const
login = config.login,
password = config.password,
unitId = config.unitId,
hostname = config.hostname || 'localhost',
port = config.port || 3033,
path = '/api/email';
if (!unitId) {
throw new Error("Parameter unitId is required");
}
//TODO
return function(message) {
//TODO validate email...
if (!message) {
return Promise.reject(new Error("Email is required"));
}
//TODO
const email = Object.assign({}, message);
email.unit_id = unitId;
//async request
return new Promise(function(resolve, reject) {
const postData = JSON.stringify(email);
const options = {
hostname: hostname,
port: port,
path: path,
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = http.request(options, (res) => {
let resobj = "";
//res.setEncoding('utf8');
res.on('data', (chunk) => {
resobj += chunk;
});
res.on('end', () => {
if (res.statusCode > 199 && res.statusCode < 300) {
resolve(JSON.parse(resobj));
} else {
reject(JSON.parse(resobj));
}
});
});
req.on('error', (e) => {
//console.error(`problem with request: ${e.message}`);
reject(e);
});
// write data to request body
req.write(postData);
req.end();
});
}
}
*/
\ No newline at end of file
package com.jh.boot.i18n;
/**
* The Interface I18nContext.
*/
public interface I18nContext {
/**
* Gets the date format.
*
* @return the date format
*/
public String getDateFormat();
/**
* Gets the currency format.
*
* @return the currency format
*/
public String getCurrencyFormat();
/**
* Gets the thousand delimiter.
*
* @return the thousand delimiter
*/
public String getThousandDelimiter();
/**
* Gets the decimal delimiter.
*
* @return the decimal delimiter
*/
public String getDecimalDelimiter();
/**
* Gets the currency.
*
* @return the currency
*/
public String getCurrency();
/**
* Gets the currency symbol.
*
* @return the currency symbol
*/
public String getCurrencySymbol();
}
package com.jh.boot.i18n;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* TODO comment.
*
* @author jh
*/
public class I18nUtils {
/** The date formats. */
private Map<String, SimpleDateFormat> dateFormats;
/** The date formatters. */
private Map<String, DateTimeFormatter> dateFormatters;
/** The number formats. */
private Map<NumberFormatKey, NumberFormat> numberFormats;
/** The instance. */
private static I18nUtils instance = new I18nUtils();
private I18nContext defaultI18n = new I18nContext() {
@Override
public String getThousandDelimiter() {
return ",";
}
@Override
public String getDecimalDelimiter() {
return ".";
}
@Override
public String getDateFormat() {
return "MM/DD/YYYY";
}
@Override
public String getCurrencySymbol() {
return "$";
}
@Override
public String getCurrencyFormat() {
return "left";
}
@Override
public String getCurrency() {
return "USD";
}
};
/**
* Instantiates a new i 18 n utils.
*/
private I18nUtils() {
dateFormats = new HashMap<>();
numberFormats = new HashMap<>();
dateFormatters = new HashMap<>();
}
/**
* Format number.
*
* @param number the number
* @param i18n the i 18 n
* @return the string
*/
public String formatNumber(Number number, I18nContext i18n) {
return formatNumber(number, 3, i18n);
}
/**
* Format number.
*
* @param number the number
* @param fixed the fixed
* @param i18n the i 18 n
* @return the string
*/
public String formatNumber(Number number, int fixed, I18nContext i18n) {
if (number == null) {
return "";
}
if (i18n == null) {
i18n = defaultI18n;
}
NumberFormatKey nfk = new NumberFormatKey(i18n.getDecimalDelimiter(), i18n.getThousandDelimiter(), fixed);
NumberFormat nf = numberFormats.get(nfk);
if (nf == null) {
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
char ds = i18n.getDecimalDelimiter() == null || i18n.getDecimalDelimiter().isEmpty() ? '.' : i18n.getDecimalDelimiter().charAt(0);
char gs = i18n.getThousandDelimiter() == null || i18n.getThousandDelimiter().isEmpty() ? '.' : i18n.getThousandDelimiter().charAt(0);
otherSymbols.setDecimalSeparator(ds);
otherSymbols.setGroupingSeparator(gs);
DecimalFormat df = new DecimalFormat("#", otherSymbols);
df.setGroupingUsed(true);
df.setGroupingSize(3);
df.setMinimumIntegerDigits(1);
df.setMinimumFractionDigits(fixed);
df.setMaximumFractionDigits(fixed);
nf = df;
numberFormats.put(nfk, df);
}
return nf.format(number);
}
/**
* Format money.
*
* @param number the number
* @param currency the currency
* @param i18n the i 18 n
* @param fixed the fixed
* @return the string
*/
public String formatMoney(Number number, String currency, I18nContext i18n, int fixed) {
if (number == null) {
return "";
}
if (i18n == null) {
i18n = defaultI18n;
}
if (currency == null) {
currency = "";
}
if (!"right".equals(i18n.getCurrencyFormat())) {
StringBuilder sb = new StringBuilder(currency);
sb.append(" ").append(formatNumber(number, fixed, i18n));
return sb.toString();
}
StringBuilder sb = new StringBuilder(formatNumber(number, fixed, i18n));
sb.append(" ").append(currency);
return sb.toString();
}
/**
* Format money.
*
* @param number the number
* @param currency the currency
* @param i18n the i 18 n
* @return the string
*/
public String formatMoney(Number number, String currency, I18nContext i18n) {
return formatMoney(number, currency, i18n, 2);
}
/**
* Format percent.
*
* @param number the number
* @param i18n the i 18 n
* @return the string
*/
public String formatPercent(Number number, I18nContext i18n) {
if (number == null) {
return "";
}
StringBuilder sb = new StringBuilder(formatNumber(number, i18n));
sb.append(" %");
return sb.toString();
}
/**
* Format date.
*
* @param date the date
* @param i18n the i 18 n
* @return the string
*/
public String formatDate(Date date, I18nContext i18n) {
if (date == null) {
return "";
}
if (i18n == null) {
i18n = defaultI18n;
}
String format = Objects.toString(i18n.getDateFormat(), "MM/dd/yyyy");
SimpleDateFormat sdf = dateFormats.get(format);
if (sdf == null) {
dateFormats.put(format, sdf = new SimpleDateFormat(format));
}
return sdf.format(date);
}
/**
* Format date.
*
* @param date the date
* @param i18n the i 18 n
* @return the string
*/
public String formatDate(LocalDate date, I18nContext i18n) {
if (date == null) {
return "";
}
if (i18n == null) {
i18n = defaultI18n;
}
String format = Objects.toString(i18n.getDateFormat(), "MM/dd/yyyy");
DateTimeFormatter dtf = dateFormatters.get(format);
if (dtf == null) {
dateFormatters.put(format, dtf = DateTimeFormatter.ofPattern(convertJSFormat(format)));
}
return date.format(dtf);
}
/**
* Convert JS format.
*
* @param format the format
* @return the string
*/
private String convertJSFormat(String format) {
return format.replace("D", "d").replace("m", "M").replace("Y","y");
}
/**
* Gets the single instance of I18nUtils.
*
* @return single instance of I18nUtils
*/
public static I18nUtils getInstance() {
return instance;
}
class NumberFormatKey {
/** The thousand delimiter. */
private String thousandDelimiter;
/** The decimal delimiter. */
private String decimalDelimiter;
/** The fixed. */
private int fixed;
/**
* Instantiates a new number format key.
*
* @param decimalDelimiter the decimal delimiter
* @param thousandDelimiter the thousand delimiter
* @param fixed the fixed
*/
public NumberFormatKey(String decimalDelimiter, String thousandDelimiter, int fixed) {
super();
this.thousandDelimiter = thousandDelimiter;
this.decimalDelimiter = decimalDelimiter;
this.fixed = fixed;
}
/**
* @return
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((decimalDelimiter == null) ? 0 : decimalDelimiter.hashCode());
result = prime * result + fixed;
result = prime * result + ((thousandDelimiter == null) ? 0 : thousandDelimiter.hashCode());
return result;
}
/**
* @param obj
* @return
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NumberFormatKey other = (NumberFormatKey) obj;
if (decimalDelimiter == null) {
if (other.decimalDelimiter != null)
return false;
} else if (!decimalDelimiter.equals(other.decimalDelimiter))
return false;
if (fixed != other.fixed)
return false;
if (thousandDelimiter == null) {
if (other.thousandDelimiter != null)
return false;
} else if (!thousandDelimiter.equals(other.thousandDelimiter))
return false;
return true;
}
}
}
package com.jh.boot.jpa;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Root;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.criteria.internal.OrderImpl;
import org.springframework.util.StringUtils;
import com.jh.boot.web.list.Page;
import com.jh.boot.web.list.PagingInfo;
import com.jh.boot.web.list.SortTrend;
/**
* TODO comment.
*
* @author jh
*/
public abstract class AbstractHibernateRepository {
/** The session factory. */
@PersistenceContext
protected EntityManager entityManager;
/**
* Criteria.
*
* @param clazz the clazz
* @return the criteria
*/
protected <T> CriteriaQuery<T> criteria(Class<T> clazz) {
return entityManager.getCriteriaBuilder().createQuery(clazz);
}
@SuppressWarnings("unchecked")
protected <T> NativeQuery<T> nativeQuery(String query) {
return (NativeQuery<T>) entityManager.createNativeQuery(query);
}
@SuppressWarnings("unchecked")
protected <T> T singleResult(Query q) {
try {
return (T) q.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
public <ID, T> T findById(Class<T> clazz, ID id) {
return entityManager.find(clazz, id);
}
/**
* TODO.
*
* @param <T> the generic type
* @param entity the entity
*/
public <T extends AbstractIdEntity> void save(T entity) {
if (entity.getId() == null) {
entityManager.persist(entity);
} else {
entityManager.merge(entity);
}
}
/**
* Delete.
*
* @param <T> the generic type
* @param entity the entity
*/
public <T extends AbstractIdEntity> void delete(T entity) {
if (entity.getId() != null) {
entityManager.remove(entity);
}
}
protected <T extends AbstractIdEntity> void synchronizeCollections(Collection<T> currentCollection, Collection<T> newCollection, BiConsumer<T, T> modifyFn, Consumer<T> modifyRelationship, boolean deleteOrphans) {
Objects.requireNonNull(currentCollection);
Objects.requireNonNull(newCollection);
Objects.requireNonNull(modifyFn);
List<T> toBeAdded = new ArrayList<>();
Map<Long, T> map = new HashMap<>();
if (newCollection != null) {
for (T nc : newCollection) {
if (nc.getId() == null) {
toBeAdded.add(nc);
} else {
map.put(nc.getId(), nc);
}
}
}
Map<Long, T> newMap = map;
Iterator<T> it = currentCollection.iterator();
while (it.hasNext()) {
T t = it.next();
T nc = newMap.get(t.getId());
if (nc == null) {
it.remove();
if (deleteOrphans) {
delete(t);
}
continue;
}
modifyFn.accept(t, nc);
}
for (T tba : toBeAdded) {
save(tba);
}
}
@SuppressWarnings("unchecked")
protected <T> Page<T> pagedCriteria(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root, PagingInfo pagingInfo) {
if (StringUtils.hasText(pagingInfo.getField())) {
cq.orderBy(new OrderImpl(root.get(pagingInfo.getField()), pagingInfo.getTrend() == SortTrend.ASCENDING));
}
Query query = entityManager.createQuery(cq);
query.setFirstResult(pagingInfo.getPage() * pagingInfo.getPageSize());
query.setMaxResults(pagingInfo.getPageSize());
List<T> resultList = query.getResultList();
CriteriaQuery<Long> count = cb.createQuery(Long.class);
Root<T> countRoot = count.from(root.getModel());
count.select(cb.count(countRoot));
if (cq.getRestriction() != null) {
count.where(cq.getRestriction());
}
Long rowsCount = entityManager.createQuery(count).getSingleResult();
return new Page<T>(pagingInfo.getPage(), pagingInfo.getPageSize(), rowsCount, resultList, pagingInfo.getField(), pagingInfo.getTrend());
}
}
package com.jh.boot.jpa;
import java.util.*;
//TODO move to jh-boot
public abstract class CollectionSync<R extends AbstractIdEntity, T extends AbstractIdEntity> {
private AbstractHibernateRepository repo;
private boolean deleteOrphans;
protected CollectionSync(AbstractHibernateRepository repo) {
this(repo, false);
}
protected CollectionSync(AbstractHibernateRepository repo, boolean deleteOrphans) {
this.repo = repo;
this.deleteOrphans = deleteOrphans;
}
public <C extends Collection<T>> C synchronize(R root, C existing, Collection<T> fresh, Class<C> clazz) {
//decide whether Set or List
if (existing == null) {
if (Set.class.isAssignableFrom(clazz)) {
existing = (C) new HashSet<T>();
} else if (List.class.isAssignableFrom(clazz)) {
existing = (C) new ArrayList<T>();
} else {
throw new IllegalArgumentException("Invalid collection type");
}
}
List<T> toBeAdded = new ArrayList<>();
Map<Long, T> map = new HashMap();
if (fresh != null) {
for (T t : fresh) {
if (t.getId() == null) {
toBeAdded.add(t);
} else {
map.put(t.getId(), t);
}
}
}
Iterator<T> it = existing.iterator();
while (it.hasNext()) {
T e = it.next();
T f = map.get(e.getId());
if (f == null) {
it.remove();
doRemove(e);
continue;
}
doMerge(e, f);
}
for (T t : toBeAdded) {
setRootToEntity(root, t);
doPersistNew(t);
existing.add(t);
}
return existing;
}
protected void doRemove(T entity) {
if (deleteOrphans) {
repo.delete(entity);
}
}
protected void doPersistNew(T entity) {
repo.save(entity);
}
protected abstract void setRootToEntity(R root, T entity);
protected abstract void doMerge(T existing, T fresh);
protected boolean isDeleteOrphans() {
return deleteOrphans;
}
protected AbstractHibernateRepository getRepo() {
return repo;
}
}
package com.jh.boot.jpa;
import java.time.LocalDate;
import java.sql.Date;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/**
* The Class LocalDateConverter.
*/
@Converter(autoApply = true)
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {
/**
* @param locDate
* @return
* @see javax.persistence.AttributeConverter#convertToDatabaseColumn(java.lang.Object)
*/
@Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}
/**
* @param sqlDate
* @return
* @see javax.persistence.AttributeConverter#convertToEntityAttribute(java.lang.Object)
*/
@Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}
\ No newline at end of file
package com.jh.boot.security;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import com.jh.boot.security.repository.AppUserRepository;
import com.jh.boot.security.service.AppUserAuthService;
/**
* The Class ReactApplicationSecurityContext.
*/
public class JhSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* @param http
* @throws Exception
* @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
HttpSecurity cfg = http
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/graphiql").permitAll()
.antMatchers("/graphql").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.clearAuthentication(true)
.permitAll()
.and();
cfg.httpBasic();
http.csrf().disable();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint());
http.headers().frameOptions().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
/**
* @param auth
* @throws Exception
* @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder)
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
/**
* Override this method to provide custom {@link AuthenticationEntryPoint}.
*
* It returns {@link RestAuthenticationEntryPoint} by default
*
* @return the authentication entry point
*/
protected AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPoint() {
@Override
public final void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
};
}
@Bean
public AuthenticationProvider authenticationProvider() {
return new AuthServiceAuthenticationProvider();
}
@Bean
public AuthService authService() {
AppUserAuthService appUserAuthService = new AppUserAuthService();
appUserAuthService.setAppUserRepository(appUserRepository());
return appUserAuthService;
}
@Bean
public AppUserRepository appUserRepository() {
return new AppUserRepository();
}
// @Bean
// public GrantedAuthorityDefaults grantedAuthorityDefaults() {
// return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
// }
}
package com.jh.boot.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import com.jh.boot.security.model.AppUser;
public class SecurityHelper {
private SecurityHelper() {
}
public static AppUser getUser() {
return (AppUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
public static AppUser getUser(Authentication auth) {
if (auth == null) {
return null;
}
return (AppUser) auth.getPrincipal();
}
public static <T extends AppUser> T getUser(Authentication auth, Class<T> clazz) {
if (AppUser.class.isAssignableFrom(clazz)) {
return (T) auth.getPrincipal();
}
return null;
}
public static boolean hasAnyRole(Authentication auth, String...roles) {
AppUser user = auth instanceof AppUserAuthentication ? ((AppUserAuthentication) auth).getUser() : null;
return hasAnyRole(user, roles);
}
public static boolean hasAnyRole(AppUser user, String... roles) {
if (user == null || user.getRolesMap() == null || roles == null || roles.length == 0) {
return false;
}
for (String role : roles) {
if (user.getRolesMap().containsKey(role)) {
return true;
}
}
return false;
}
}
/*
* Created on 24. 1. 2018 9:08:52
*
*/
package com.jh.boot.security.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import com.jh.boot.jpa.AbstractIdEntity;
/**
* The Class AppRole.
*
* @author Jan Hrabal
*/
@Entity
@Table(name = "APP_ROLE")
public class AppRole extends AbstractIdEntity {
private static final long serialVersionUID = 1L;
@Column(name = "NAME")
private String name;
public AppRole() {
super();
}
public AppRole(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.jh.boot.security.repository;
import java.util.Date;
import javax.persistence.Query;
import org.springframework.util.StringUtils;
import com.jh.boot.jpa.AbstractHibernateRepository;
import com.jh.boot.security.PasswordHash;
import com.jh.boot.security.PasswordUtils;
import com.jh.boot.security.model.AppRole;
import com.jh.boot.security.model.AppUser;
import com.jh.boot.security.model.ResetPasswordToken;
public class AppUserRepository extends AbstractHibernateRepository {
public AppUser findByLogin(String username) {
if (!StringUtils.hasText(username)) {
return null;
}
Query q = entityManager.createQuery("select au from AppUser au where lower(au.login) = :login and (au.deleted is null or au.deleted = false)");
q.setParameter("login", username.trim().toLowerCase());
return singleResult(q);
}
public AppUser fetchByLoginDetached(String username) {
if (!StringUtils.hasText(username)) {
return null;
}
Query q = entityManager.createQuery("select au from AppUser au left join fetch au.roles where lower(au.login) = :login and (au.deleted is null or au.deleted = false)");
q.setParameter("login", username.trim().toLowerCase());
AppUser user = singleResult(q);
if (user == null) {
return null;
}
entityManager.detach(user);
return user;
}
public AppUser registerUser(String username, String password) {
AppUser user = new AppUser();
user.setLogin(username);
PasswordHash hash = PasswordUtils.hashPassword(password);
user.setPassword(hash.getHash());
user.setPasswordSalt(hash.getSalt());
user.setAccountEnabled(true);
user.setAccountExpired(false);
user.setPasswordChanged(new Date());
user.setPasswordExpired(false);
entityManager.persist(user);
return user;
}
public ResetPasswordToken saveResetPasswordToken(ResetPasswordToken token) {
entityManager.persist(token);
return token;
}
public ResetPasswordToken findResetPasswordToken(String login, String token) {
if (!StringUtils.hasText(login) || !StringUtils.hasText(token)) {
return null;
}
Query q = entityManager.createQuery("select au from ResetPasswordToken au where lower(au.login) = :login and lower(au.token) = :token and (au.used is null or au.used = :used)");
q.setParameter("login", login.trim().toLowerCase());
q.setParameter("token", token.trim().toLowerCase());
q.setParameter("used", Boolean.FALSE);
return singleResult(q);
}
public AppRole findRole(String name) {
Query q = entityManager.createQuery("select ar from AppRole ar where lower(ar.name) = :name");
q.setParameter("name", name.trim().toLowerCase());
return singleResult(q);
}
}
package com.jh.boot.security.utils;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import com.jh.boot.email.Email;
import com.jh.boot.email.EmailRecipient;
import com.jh.boot.email.EmailService;
import com.jh.boot.email.RecipientType;
import com.jh.boot.security.AuthServiceListener;
import com.jh.boot.security.model.AppUser;
import com.jh.boot.security.model.ResetPasswordToken;
import com.jh.boot.template.TemplateService;
public class TemplateEmailAuthServiceListener implements AuthServiceListener {
@Autowired
private EmailService emailService;
@Autowired
private TemplateService templateService;
@Value("${template.email.signup.subject:email.signup.subject}")
private String signupSubjectCode;
@Value("${template.email.signup.text:email.signup.text}")
private String signupTemplateCode;
@Value("${template.email.signup.html:email.signup.html}")
private String signupTemplateHtmlCode;
@Value("${template.email.password.subject:email.password.subject}")
private String passwordSubjectCode;
@Value("${template.email.password.text:email.password.text}")
private String passwordTemplateCode;
@Value("${template.email.password.html:email.password.html}")
private String passwordTemplateHtmlCode;
@Value("${hostname.base:http://localhost:3000}")
private String hostnameBase;
@Override
public void registerUser(AppUser user, String password) {
Map<String, Object> data = new HashMap<>();
data.put("login", user.getLogin());
data.put("password", password);
data.put("loginPath", relativePath("/login"));
sendEmail(signupSubjectCode, signupTemplateCode, signupTemplateHtmlCode, user, data);
}
@Override
public void generateResetToken(AppUser user, ResetPasswordToken token) {
Map<String, Object> data = new HashMap<>();
data.put("resetPasswordUrl", relativePath("/resetPassword") + "?token=" + token.getToken());
sendEmail(passwordSubjectCode, passwordTemplateCode, passwordTemplateHtmlCode, user, data);
}
@Override
public void deleteUser(AppUser user) {
//TODO
}
protected void sendEmail(String subject, String content, String html, AppUser user, Map<String, Object> data) {
Locale locale = user.getLocale() == null ? Locale.getDefault() : new Locale(user.getLocale());
subject = templateService.evaluate(subject, data, locale);
content = templateService.evaluate(content, data, locale);
html = templateService.evaluate(html, data, locale);
Email email = new Email();
email.setRecipients(Collections.singleton(new EmailRecipient(user.getEmail(), RecipientType.TO)));
email.setSubject(subject);
email.setText(content);
email.setHtml(html);
emailService.sendEmail(email);
}
protected String relativePath(String path) {
java.net.URI uri = null;
try {
uri = new java.net.URI (hostnameBase);
} catch (URISyntaxException e) {
throw new IllegalStateException("Cannot resolve URI", e);
}
return uri.resolve(path).toString();
}
}
package com.jh.boot.template;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
public class HibernateLoaderTemplateService implements TemplateService {
private static final Logger LOG = LoggerFactory.getLogger(HibernateLoaderTemplateService.class);
private TemplateLoader loader;
private TemplateEngine engine;
private TemplateValuesConfig valuesConfig;
@Override
@Transactional
public String evaluate(String templateCode, Map<String, Object> data, Locale locale) {
Template t = loader.loadTemplate(templateCode, locale);
if (t == null) {
LOG.warn("Cannot find template {}", templateCode);
return null;
}
Map<String, Object> values = new HashMap<String, Object>();
if (valuesConfig != null) {
values.putAll(valuesConfig.getValues());
}
if (data != null) {
values.putAll(data);
}
String content = t.getTemplate();
StringWriter sw = new StringWriter();
engine.evaluate(sw, content, values);
content = sw.toString();
if (t.getLayoutCode() != null) {
t = loader.loadTemplate(t.getLayoutCode(), locale);
if (t != null) {
values.put("__layout_content__", content);
}
sw = new StringWriter();
engine.evaluate(sw, t.getTemplate(), values);
content = sw.toString();
}
return content;
}
@Autowired
public void setLoader(TemplateLoader loader) {
this.loader = loader;
}
@Autowired
public void setEngine(TemplateEngine engine) {
this.engine = engine;
}
@Autowired
public void setValuesConfig(TemplateValuesConfig valuesConfig) {
this.valuesConfig = valuesConfig;
}
}
package com.jh.boot.template;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
public class HibernateTemplateLoader implements TemplateLoader {
@Autowired
private HibernateTemplateRepository repository;
@Override
@Transactional
public Template loadTemplate(String code, Locale locale) {
Template t = null;
if (locale != null) {
if (StringUtils.hasText(locale.getCountry())) {
t = repository.loadTemplate(code, locale.getLanguage() + "-" + locale.getCountry());
}
if (t == null) {
t = repository.loadTemplate(code, locale.getLanguage());
}
}
if (t == null) {
t = repository.loadTemplate(code, null);
}
return t;
}
}
package com.jh.boot.template;
import java.util.List;
import javax.persistence.TypedQuery;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import com.jh.boot.jpa.AbstractHibernateRepository;
@Repository
public class HibernateTemplateRepository extends AbstractHibernateRepository {
public Template loadTemplate(String code, String locale) {
if (code == null) {
return null;
}
String hql = "select t from Template t where lower(code) = :code";
if (StringUtils.hasText(locale)) {
hql += " and lower(locale) = :locale";
} else {
hql += " and locale is null";
}
TypedQuery<Template> q = entityManager.createQuery(hql, Template.class);
q.setParameter("code", code.toLowerCase());
if (StringUtils.hasText(locale)) {
q.setParameter("locale", locale.toLowerCase());
}
List<Template> list = q.getResultList();
return list == null || list.isEmpty() ? null : list.get(0);
}
}
package com.jh.boot.template;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import com.jh.boot.jpa.AbstractIdEntity;
@Entity
@Table(name = "TEMPLATE")
public class Template extends AbstractIdEntity {
@Column(name = "CODE")
private String code;
@Column(name = "LAYOUT_CODE")
private String layoutCode;
@Column(name = "TEMPLATE")
private String template;
@Column(name = "LOCALE")
private String locale;
public Template() {
super();
}
public Template(Long templateId) {
super();
setId(templateId);
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getLayoutCode() {
return layoutCode;
}
public void setLayoutCode(String name) {
this.layoutCode = name;
}
public String getTemplate() {
return template;
}
public void setTemplate(String template) {
this.template = template;
}
}
package com.jh.boot.template;
import java.io.Writer;
import java.util.Map;
public interface TemplateEngine {
void evaluate(Writer writer, String templateContent, Map<String, Object> data);
}
\ No newline at end of file
package com.jh.boot.template;
import java.util.Locale;
public interface TemplateLoader {
Template loadTemplate(String code, Locale locale);
}
package com.jh.boot.template;
import java.util.Locale;
import java.util.Map;
public interface TemplateService {
String evaluate(String templateCode, Map<String, Object> data, Locale locale);
}
package com.jh.boot.template;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "template")
public class TemplateValuesConfig {
private Map<String, String> values;
public Map<String, String> getValues() {
return values;
}
public void setValues(Map<String, String> values) {
this.values = values;
}
}
package com.jh.boot.template.handlebars;
import java.io.IOException;
import java.io.Writer;
import java.text.MessageFormat;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.github.jknack.handlebars.Options;
import com.github.jknack.handlebars.Template;
import com.github.jknack.handlebars.context.JavaBeanValueResolver;
import com.github.jknack.handlebars.context.MapValueResolver;
import com.jh.boot.i18n.I18nContext;
import com.jh.boot.i18n.I18nUtils;
import com.jh.boot.template.TemplateEngine;
import com.jh.boot.template.TemplateLoader;
/**
*
*
* {{#if author}}
* <h1>{{firstName}} {{lastName}}</h1>
* {{else}}
* <h1>Unknown Author</h1>
* {{/if}}
*
*
* {{#each array}}
{{@index}}: {{this}}
{{/each}}
*
*
*{{#each array as |value key|}}
{{#each child as |childValue childKey|}}
{{key}} - {{childKey}}. {{childValue}}
{{/each}}
{{/each}}
*
* {{#with author}}
<p>{{name}}</p>
{{else}}
<p class="empty">No content</p>
{{/with}}
{{#with author as |myAuthor|}}
<h2>By {{myAuthor.firstName}} {{myAuthor.lastName}}</h2>
{{/with}}
*
* Nested handlebars paths can also include ../ segments, which evaluate their paths against a parent context.
*
*
* @author Jan Hrabal
*/
public class HandlebarsTemplateEngine implements TemplateEngine {
private boolean useCache = false;
private Map<String, Template> templateCache;
private Handlebars handlebars;
/**
* Initializes instance.
*/
@PostConstruct
public void init() {
templateCache = new HashMap<>();
handlebars = new Handlebars();
handlebars.setParentScopeResolution(true);
handlebars.setPreEvaluatePartialBlocks(false);
//conditional helpers
handlebars.registerHelper("eq", new Helper<Object>() {
public CharSequence apply(Object a, Options options) throws IOException {
Object b = options.param(0, null);
boolean result = Objects.equals(a, b);
if (!result) {
result = Objects.equals(Objects.toString(a, null), Objects.toString(b, null));
}
return result ? options.fn() : options.inverse();
}
});
I18nUtils i18nUtils = I18nUtils.getInstance();
handlebars.registerHelper("formatNumber", new Helper<Number>() {
public CharSequence apply(Number num, Options options) throws IOException {
I18nContext i18nCtx = (I18nContext) options.param(0);
return i18nUtils.formatNumber(num, i18nCtx);
}
});
handlebars.registerHelper("formatPercent", new Helper<Number>() {
public CharSequence apply(Number num, Options options) throws IOException {
I18nContext i18nCtx = (I18nContext) options.param(0);
return i18nUtils.formatPercent(num, i18nCtx);
}
});
handlebars.registerHelper("formatMoney", new Helper<Number>() {
public CharSequence apply(Number num, Options options) throws IOException {
String currency = (String) options.param(0);
I18nContext i18nCtx = (I18nContext) options.param(1);
return i18nUtils.formatMoney(num, currency, i18nCtx);
}
});
handlebars.registerHelper("formatDate", new Helper<LocalDate>() {
public CharSequence apply(LocalDate date, Options options) throws IOException {
I18nContext i18nCtx = (I18nContext) options.param(0);
return i18nUtils.formatDate(date, i18nCtx);
}
});
handlebars.registerHelper("formatLabel", new Helper<String>() {
public CharSequence apply(String key, Options options) throws IOException {
if (options.params == null || options.params.length < 1) {
return "Wrong formatLabel syntax for key " + key + ". It should be formatLabel key labels ...params";
}
Map<String, Object> labels = (Map<String, Object>) options.params[0];
if (labels == null) {
return "!!" + key;
}
String label = (String) labels.get(key);
if (label == null) {
return "!!" + key;
}
Object[] messageParams = options.params.length > 1 ? Arrays.copyOfRange(options.params, 1, options.params.length) : new Object[0];
return MessageFormat.format(label, messageParams);
}
});
}
@Override
public void evaluate(Writer writer, String template, Map<String, Object> data) {
String name = "inline://" + template;
Template t = useCache ? templateCache.get(name) : null;
if (t == null) {
try {
t = handlebars.compileInline(template);
} catch (Exception e) {
throw new RuntimeException(String.format("Inline template '%s' cannot be read", template), e);
}
if (useCache) {
templateCache.put(name, t);
}
}
evaluateTemplate(t, data, writer);
}
protected void evaluateTemplate(Template t, Map<String, Object> data, Writer writer) {
Context context = Context
.newBuilder(data)
.combine(data)
.resolver(JavaBeanValueResolver.INSTANCE, MapValueResolver.INSTANCE)
.build();
try {
t.apply(context, writer);
} catch (IOException e) {
throw new RuntimeException("Cannot evaluate template", e);
}
}
/**
* Sets the use cache.
*
* @param useCache the new use cache
*/
@Value("${global.caching:true}")
public void setUseCache(boolean useCache) {
this.useCache = useCache;
}
}
package com.jh.boot.web;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.jh.boot.jpa.AbstractIdEntity;
import com.jh.boot.web.list.Page;
import com.jh.boot.web.list.SortTrend;
public class Converter {
private Converter() {}
public static <S, D> D convert(S source, Function<S, D> mappingFunction) {
if (source == null || mappingFunction == null) {
return null;
}
return mappingFunction.apply(source);
}
public static <S, D> Set<D> convertSet(Collection<S> list, Function<S, D> mappingFunction) {
if (list == null) {
return null;
}
return list.stream().map(mappingFunction).collect(Collectors.toSet());
}
public static <S, D> List<D> convertList(Collection<S> list, Function<S, D> mappingFunction) {
if (list == null) {
return null;
}
return list.stream().map(mappingFunction).collect(Collectors.toList());
}
public static <S, D> Page<D> convertPage(Page<S> page, Function<S, D> mappingFunction) {
if (page == null || mappingFunction == null) {
return null;
}
List<D> content = new ArrayList<>();
if (page.getContent() != null) {
for (S s : page.getContent()) {
content.add(mappingFunction.apply(s));
}
}
return new Page<D>(page.getPage(), page.getPagesCount(), page.getPageSize(), page.getTotalElements(), content, page.getSortBy(), SortTrend.parse(page.getTrend()));
}
public static <T> List<IdNameDto> mapToDtos(Collection<T> collection, Function<T, Long> getId, Function<T, String> getName) {
if (collection == null || collection.isEmpty() || getId == null || getName == null) {
return Collections.emptyList();
}
List<IdNameDto> result = new ArrayList<IdNameDto>();
for (T t : collection) {
result.add(new IdNameDto(getId.apply(t), getName.apply(t)));
}
return result;
}
//public static <T> T toEntity(IdNameDto )
/**
* Helper function to safely get id
*
* @param entity
* @return
*/
public static Long getId(AbstractIdEntity entity) {
return entity == null ? null : entity.getId();
}
}
package com.jh.boot.web;
import java.util.StringJoiner;
import org.springframework.util.StringUtils;
import com.jh.boot.jpa.AbstractIdEntity;
import com.jh.boot.security.model.AppUser;
public class ConverterUtils {
public static Long id(AbstractIdEntity user) {
return user == null ? null : user.getId();
}
public static String name(AppUser user) {
if (user == null) {
return null;
}
StringJoiner sj = new StringJoiner(" ");
if (StringUtils.hasText(user.getFirstName())) {
sj.add(user.getFirstName());
}
if (StringUtils.hasText(user.getLastName())) {
sj.add(user.getLastName());
}
return sj.toString();
}
}
/*
* Created on 29. 1. 2018 13:40:45
*
*/
package com.jh.boot.web;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.util.WebUtils;
/**
* The Class FallbackLocaleResolver.
*
* @author Jan Hrabal
*/
public class FallbackLocaleResolver extends AcceptHeaderLocaleResolver/* LocaleResolver*/ {
/** The locales string. */
@Value("${app.locales:en}")
private String localesString;
/** The default locale. */
@Value("${app.locale.default:en}")
private String defaultLocale;
/** The default country. */
@Value("${app.locale.defaultCountry:US}")
private String defaultCountry;
/** The locales. */
private Set<String> locales;
/**
* Inits the.
*/
@PostConstruct
public void init() {
locales = new LinkedHashSet<>();
if (localesString != null) {
String[] ls = localesString.split("[\\s,;]");
for (String s : ls) {
if (StringUtils.hasText(s)) {
locales.add(s.trim().toLowerCase());
}
}
} else {
locales.add("en");//TODO default config?
}
if (defaultLocale == null) {
defaultLocale = "en";
} else {
defaultLocale = defaultLocale.trim().toLowerCase();
}
}
/**
* Resolve locale.
*
* @param httpRequest the http request
* @return the locale
* @see org.springframework.web.servlet.LocaleResolver#resolveLocale(javax.servlet.http.HttpServletRequest)
*/
@Override
public Locale resolveLocale(HttpServletRequest httpRequest) {
String code = null;
//get param
String lang = httpRequest.getParameter("lang");
if (StringUtils.hasText(lang)) {
if (locales.contains(langCode(lang))) {
code = lang;
}
}
Cookie c = WebUtils.getCookie(httpRequest, "lang");
if (c != null) {
lang = c.getValue();
if (StringUtils.hasText(lang)) {
if (locales.contains(langCode(lang))) {
code = lang;
}
}
}
if (code == null) {
String acceptLanguage = httpRequest.getHeader("Accept-Language");
if (StringUtils.hasText(acceptLanguage)) {
String[] als = acceptLanguage.split(",");
for (String s : als) {
if (locales.contains(langCode(s))) {
code = s;
break;
}
}
}
}
String country = null;
if (code == null) {
code = defaultLocale;
country = defaultCountry;
} else {
country = countryCode(code);
code = langCode(code);
}
return country == null ? new Locale(code) : new Locale(code, country);
}
/**
* Sets the locale.
*
* @param arg0 the arg 0
* @param arg1 the arg 1
* @param arg2 the arg 2
* @see org.springframework.web.servlet.LocaleResolver#setLocale(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.util.Locale)
*/
@Override
public void setLocale(HttpServletRequest arg0, HttpServletResponse arg1, Locale arg2) {
// TODO do nothing
}
/**
* Lang code.
*
* @param s the s
* @return the string
*/
protected String langCode(String s) {
if (s == null) {
return defaultLocale;
}
s = s.trim().toLowerCase();
if (s.length() > 2) {
return s.substring(0, 2);
}
return s;
}
/**
* Lang name.
*
* @param s the s
* @return the string
*/
protected String langName(String s) {
if (s == null) {
return defaultLocale;
}
return s.trim().replace("-", "_");
}
/**
* Country code.
*
* @param s the s
* @return the string
*/
protected String countryCode(String s) {
if (s == null || s.length() < 5 ) {
return null;
}
return s.substring(3);
}
}
package com.jh.boot.web;
import org.springframework.http.HttpStatus;
import org.springframework.orm.hibernate5.HibernateOptimisticLockingFailureException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* The Class GlobalControllerExceptionHandler.
*/
@ControllerAdvice
class GlobalControllerExceptionHandler {
/**
* Handle conflict.
*/
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(HibernateOptimisticLockingFailureException.class)
public void handleConflict() {
}
}
\ No newline at end of file
package com.jh.boot.web;
public class IdNameDto {
private Long id;
private String name;
public IdNameDto() {
}
public IdNameDto(Long id, String name) {
super();
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.jh.boot.web;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module.Feature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.jh.boot.web.list.PagingArgumentResolver;
import com.jh.boot.web.list.SortingArgumentResolver;
public class JhWebConfig implements WebMvcConfigurer {
/**
* @param converters
* @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#configureMessageConverters(java.util.List)
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper());
converters.add(converter);
}
/**
* Object mapper.
*
* @return the object mapper
*/
@Bean
public ObjectMapper objectMapper() {
ObjectMapper om = new ObjectMapper();
om.setSerializationInclusion(Include.NON_NULL);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
om.registerModule(new JavaTimeModule());
Hibernate5Module module = new Hibernate5Module();
module.disable(Feature.USE_TRANSIENT_ANNOTATION);
module.enable(Feature.REPLACE_PERSISTENT_COLLECTIONS);
om.registerModule(module);
return om;
}
/**
* @param argumentResolvers
* @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#addArgumentResolvers(java.util.List)
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new PagingArgumentResolver());
argumentResolvers.add(new SortingArgumentResolver());
}
/**
* Locale resolver.
*
* @return the locale resolver
*/
@Bean
@Primary
public LocaleResolver localeResolver() {
return new FallbackLocaleResolver();
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
/**
* @param configurer
* @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#configurePathMatch(org.springframework.web.servlet.config.annotation.PathMatchConfigurer)
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
// .setUseTrailingSlashMatch(false)
// .setUseRegisteredSuffixPatternMatch(true)
// .setPathMatcher(antPathMatcher())
// .setUrlPathHelper(urlPathHelper());
}
}
package com.jh.boot.web;
import java.beans.PropertyEditorSupport;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
/**
* The Class LocalDateControllerAdvice.
*/
@ControllerAdvice
public class LocalDateControllerAdvice {
/**
* Inits the binder.
*
* @param binder the binder
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDate.parse(text, DateTimeFormatter.ISO_DATE));
}
});
}
}
\ No newline at end of file
/*
* Created on 9. 11. 2017 10:26:30
*
*/
package com.jh.boot.web.error;
import java.util.Collection;
/**
* The Class ErrorMessagesException.
*
* @author Jan Hrabal
*/
public abstract class ErrorMessagesException extends RuntimeException implements ErrorMessages {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The errors. */
private ErrorMessage[] errors;
/**
* Instantiates a new error messages exception.
*
* @param errors the errors
*/
public ErrorMessagesException(ErrorMessage...errors) {
super();
this.errors = errors;
}
/**
* Instantiates a new error messages exception.
*
* @param errors the errors
*/
public ErrorMessagesException(Collection<ErrorMessage> errors) {
super();
ErrorMessage[] errs = new ErrorMessage[0];
this.errors = errors == null ? errs : errors.toArray(errs);
}
/**
* Gets the error messages.
*
* @return the error messages
* @see de.dhl.spms.api.ErrorMessages#getErrorMessages()
*/
@Override
public ErrorMessage[] getErrorMessages() {
return errors;
}
}
package com.jh.boot.web.error;
import java.util.Collection;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* The Class NotFoundException.
*/
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class NotFoundException extends RestApiException {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/**
* Instantiates a new not found exception.
*
* @param errors the errors
*/
public NotFoundException(Collection<ErrorMessage> errors) {
super(HttpStatus.NOT_FOUND, errors);
}
/**
* Instantiates a new not found exception.
*
* @param errors the errors
*/
public NotFoundException(ErrorMessage... errors) {
super(HttpStatus.NOT_FOUND, errors);
}
}
/*
* Created on 24. 1. 2018 8:46:58
*
*/
package com.jh.boot.web.error;
import java.util.Collection;
import org.springframework.http.HttpStatus;
/**
* The Class RestApiException.
*
* @author Jan Hrabal
*/
public class RestApiException extends ErrorMessagesException implements ErrorStatus {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The status. */
private HttpStatus status;
/**
* Instantiates a new rest api exception.
*
* @param status the status
* @param errors the errors
*/
public RestApiException(HttpStatus status, ErrorMessage... errors) {
super(errors);
this.status = status;
}
/**
* Instantiates a new rest api exception.
*
* @param status the status
* @param errors the errors
*/
public RestApiException(HttpStatus status, Collection<ErrorMessage> errors) {
super(errors);
this.status = status;
}
/**
* Gets the error status.
*
* @return the error status
* @see com.jh.boot.web.error.ErrorStatus#getErrorStatus()
*/
@Override
public HttpStatus getErrorStatus() {
return status;
}
}
package com.jh.boot.web.error;
import java.util.Collection;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* The Class ValidationFailedException.
*/
@ResponseStatus(value = HttpStatus.FORBIDDEN)
public class SecurityViolationException extends RestApiException {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/**
* Instantiates a new validation failed exception.
*
* @param errors the errors
*/
public SecurityViolationException(Collection<ErrorMessage> errors) {
super(HttpStatus.FORBIDDEN, errors);
}
/**
* Instantiates a new validation failed exception.
*
* @param errors the errors
*/
public SecurityViolationException(ErrorMessage... errors) {
super(HttpStatus.FORBIDDEN, errors);
}
}
package com.jh.boot.web.error;
import java.util.Collection;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* The Class ValidationFailedException.
*/
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public class ValidationFailedException extends RestApiException {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/**
* Instantiates a new validation failed exception.
*
* @param errors the errors
*/
public ValidationFailedException(Collection<ErrorMessage> errors) {
super(HttpStatus.BAD_REQUEST, errors);
}
/**
* Instantiates a new validation failed exception.
*
* @param errors the errors
*/
public ValidationFailedException(ErrorMessage... errors) {
super(HttpStatus.BAD_REQUEST, errors);
}
}
/*
* Created on 25. 8. 2017 18:29:24
*
*/
package com.jh.boot.web.list;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* The Interface DefaultSorting.
*
* @author Jan Hrabal
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
public @interface DefaultSorting {
/**
* Field.
*
* @return the string
*/
String field();
/**
* Trend.
*
* @return the sort trend
*/
SortTrend trend() default SortTrend.ASCENDING;
}
package com.jh.boot.web.list;
/**
* Default implementation of {@link SortingInfo}.
*
* @author jh
*/
public class DefaultSortingInfo implements SortingInfo {
/** The field. */
private String field;
/** The trend. */
private SortTrend trend;
/**
* Instantiates a new default sorting info.
*
* @param field the field
* @param trend the trend
*/
public DefaultSortingInfo(String field, SortTrend trend) {
super();
this.field = field;
this.trend = trend;
}
/**
* @return
* @see com.jh.boot.web.list.SortingInfo#getField()
*/
@Override
public String getField() {
return field;
}
/**
* @return
* @see com.jh.boot.web.list.SortingInfo#getTrend()
*/
@Override
public SortTrend getTrend() {
return trend;
}
/**
* Asc.
*
* @param field the field
* @return the sorting info
*/
public static final SortingInfo asc(String field) {
return new DefaultSortingInfo(field, SortTrend.ASCENDING);
}
/**
* Desc.
*
* @param field the field
* @return the sorting info
*/
public static final SortingInfo desc(String field) {
return new DefaultSortingInfo(field, SortTrend.DESCENDING);
}
}
\ No newline at end of file
/*
* Created on 3. 11. 2016 9:19:23
*
*/
package com.jh.boot.web.list;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.NativeWebRequest;
import com.jh.boot.utils.Utils;
/**
* The Class ListHelper.
*/
public class ListHelper {
/** The Constant DEFAULT_PAGE_SIZE. */
public static final int DEFAULT_PAGE_SIZE = 10;
/**
* Read paging info.
*
* @param request the request
* @param defaultField the default field
* @param defaultTrend the default trend
* @return the paging info
*/
public static PagingInfo readPagingInfo(NativeWebRequest request, String defaultField, SortTrend defaultTrend) {
if (request == null) {
return new DefaultPagingInfo();
}
Integer page = 0;
Integer pageSize = 10;
/*
if (Utils.isTrue(request.getHeader("X-Paging"))) {
String s = request.getHeader("X-Paging-Page");
page = Utils.parseInt(s, 0);
s = request.getHeader("X-Paging-PageSize");
pageSize = Utils.parseInt(s, DEFAULT_PAGE_SIZE);
}
*/
page = Utils.parseInt(request.getParameter("page"), 0);
pageSize = Utils.parseInt(request.getParameter("pageSize"), DEFAULT_PAGE_SIZE);
SortingInfo si = readSortingInfo(request, defaultField, defaultTrend);
return si == null ? new DefaultPagingInfo(page, pageSize) : new DefaultPagingInfo(page, pageSize, si.getField(), si.getTrend());
}
public static PagingInfo sortedPagingInfo(PagingInfo pi, String sortField, SortTrend trend) {
return new DefaultPagingInfo(pi.getPage(), pi.getPageSize(), sortField, trend);
}
/**
* Read paging info.
*
* @param request the request
* @return the paging info
*/
public static PagingInfo readPagingInfo(NativeWebRequest request) {
return readPagingInfo(request, null, null);
}
/**
* Read sorting info.
*
* @param request the request
* @param defaultField the default field
* @param defaultTrend the default trend
* @return the sorting info
*/
public static SortingInfo readSortingInfo(NativeWebRequest request, String defaultField, SortTrend defaultTrend) {
if (request == null) {
return null;
}
if (!(StringUtils.hasText(request.getParameter("sortBy")) || defaultField != null)) {
return null;
}
String field = null;
String trend = null;
SortTrend st = null;
field = request.getParameter("sortBy");
trend = request.getParameter("sort");
if (!StringUtils.hasText(field) && StringUtils.hasText(defaultField)) {
field = defaultField;
}
if (!StringUtils.hasText(trend)) {
if (defaultTrend != null) {
st = defaultTrend;
}
} else {
st = SortTrend.parse(trend);
}
if (!StringUtils.hasText(field) || st == null) {
return null;
}
return new DefaultSortingInfo(field, st);
}
// /**
// * Write paging info.
// *
// * @param page the page
// * @return the http headers
// */
// public static HttpHeaders writePagingInfo(Page<?> page) {
// return writePagingInfo(new HttpHeaders(), page);
// }
//
//
// /**
// * Writes complete headers for provided page .
// *
// * @param headers the headers
// * @param page the page
// * @return the http headers
// */
// public static HttpHeaders writePagingInfo(HttpHeaders headers, Page<?> page) {
// if (page == null) {
// return headers;
// }
//
// headers.add("X-Paging", "true");
// headers.add("X-Paging-Page", String.valueOf(page.getPage()));
// headers.add("X-Paging-PagesCount", String.valueOf(page.getPagesCount()));
//
// writeSortingInfo(headers, page);
//
// return headers;
// }
// /**
// * Writes only sorting information for provided page.
// *
// * @param headers the headers
// * @param page the page
// * @return the http headers
// */
// public static HttpHeaders writeSortingInfo(HttpHeaders headers, Page<?> page) {
// if (page == null || !page.isSorted()) {
// return headers;
// }
//
// headers.add("X-Sorting", Objects.toString(page.isSorted()));
// if (page.isSorted()) {
// headers.add("X-Sorting-Field", page.getSortBy());
// headers.add("X-Sorting-Trend", page.getTrend() == SortTrend.DESCENDING ? "desc" : "asc");
// }
//
// return headers;
// }
// /**
// * Creates paged response entity.
// *
// * @param <T> the generic type
// * @param page the page
// * @return the response entity
// */
// public static <T> ResponseEntity<List<T>> pagedResponse(Page<T> page) {
// return new ResponseEntity<>(page.getContent(), ListHelper.writePagingInfo(page), HttpStatus.OK);
// }
}
/**
* Default implementation for {@link PagingInfo}
*
* @author Jan Hrabal
*/
class DefaultPagingInfo implements PagingInfo {
private int pageSize;
private int page;
private String field;
private SortTrend sortTrend;
public DefaultPagingInfo() {
this(null, null);
}
public DefaultPagingInfo(Integer page, Integer pageSize) {
this(page, pageSize, null, null);
}
public DefaultPagingInfo(Integer page, Integer pageSize, String field, SortTrend sortTrend) {
super();
this.pageSize = pageSize == null || pageSize < 1 ? 20 : pageSize;
this.page = page == null ? 0 : page;
this.field = field;
this.sortTrend = sortTrend;
}
@Override
public int getPageSize() {
return pageSize;
}
@Override
public int getPage() {
return page;
}
@Override
public String getField() {
return field;
}
@Override
public SortTrend getTrend() {
return sortTrend;
}
}
\ No newline at end of file
/*
* Created on 12. 10. 2016 13:01:20
*
*/
package com.jh.boot.web.list;
import java.util.Collections;
import java.util.List;
/**
* TODO.
*
* @author Jan Hrabal
* @param <T> the generic type
*/
public class Page<T> {
/** The content. */
private List<T> content;
/** The pages count. */
private int pagesCount;
/** The page. */
private int page;
private int pageSize;
/** The sort by. */
private String sortBy;
/** The trend. */
private SortTrend trend;
private int totalElements;
/**
* Instantiates a new page.
*
* @param content the content
*/
public Page(List<T> content) {
this(0, 1, content.size(), content);
}
/**
* Instantiates a new page.
*
* @param page the page
* @param pagesCount the pages count
* @param content the content
*/
public Page(int page, int pagesCount, int pageSize, List<T> content) {
this.content = content;
this.page = page;
this.pagesCount = pagesCount;
this.pageSize = pageSize;
}
/**
* Instantiates a new page.
*
* @param page the page
* @param pagesCount the pages count
* @param content the content
* @param sortBy the sort by
* @param trend the trend
*/
public Page(int page, int pagesCount, int pageSize, List<T> content, String sortBy, SortTrend trend) {
super();
this.content = content;
this.pagesCount = pagesCount;
this.page = page;
this.sortBy = sortBy;
this.trend = trend;
this.pageSize = pageSize;
}
public Page(int page, int pagesCount, int pageSize, int totalElementsCount, List<T> content, String sortBy, SortTrend trend) {
super();
this.content = content;
this.pagesCount = pagesCount;
this.totalElements = totalElementsCount;
this.page = page;
this.sortBy = sortBy;
this.trend = trend;
this.pageSize = pageSize;
}
public Page(int page, int pageSize, long totalElements, List<T> content, String sortBy, SortTrend trend) {
super();
this.content = content;
this.sortBy = sortBy;
this.trend = trend;
this.totalElements = (int) totalElements;
this.pageSize = pageSize;
this.page = this.totalElements > 0 ? Math.min(page, this.totalElements / Math.max(pageSize, 1)) : 0;
this.pagesCount = this.totalElements > 0 ? (this.totalElements + pageSize / 2) / this.pageSize : 1;
}
/**
* Gets the content.
*
* @return the content
*/
public List<T> getContent() {
return content == null ? Collections.emptyList() : content;
}
/**
* Gets the pages count.
*
* @return the pages count
*/
public int getPagesCount() {
return pagesCount;
}
/**
* Gets the page.
*
* @return the page
*/
public int getPage() {
return page;
}
/**
* Gets the sort by.
*
* @return the sort by
*/
public String getSortBy() {
return sortBy;
}
/**
* Gets the trend.
*
* @return the trend
*/
public String getTrend() {
return trend == null ? null : trend.getTrend();
}
/**
* Checks if is sorted.
*
* @return true, if is sorted
*/
public boolean isSorted() {
return sortBy != null && trend != null;
}
public int getTotalElements() {
return totalElements;
}
public static <T> Page<T> empty() {
return new Page<T>(0, 0, ListHelper.DEFAULT_PAGE_SIZE, Collections.emptyList());
}
public int getPageSize() {
return pageSize;
}
}
package com.jh.boot.web.list;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* The Class PagingArgumentResolver.
*/
public class PagingArgumentResolver implements HandlerMethodArgumentResolver {
/**
* @param parameter
* @return
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter)
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(PagingInfo.class);
}
/**
* @param parameter
* @param mavContainer
* @param webRequest
* @param binderFactory
* @return
* @throws Exception
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory)
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
DefaultSorting defaultSorting = parameter.getMethodAnnotation(DefaultSorting.class);
if (defaultSorting == null) {
defaultSorting = parameter.getParameterAnnotation(DefaultSorting.class);
}
if (defaultSorting != null) {
return ListHelper.readPagingInfo(webRequest, defaultSorting.field(), defaultSorting.trend());
}
return ListHelper.readPagingInfo(webRequest);
}
}
\ No newline at end of file
/*
* Created on 13. 10. 2016 17:11:34
*
*/
package com.jh.boot.web.list;
/**
* TODO.
*
* @author Jan Hrabal
*/
public interface PagingInfo extends SortingInfo {
/**
* Gets the page size.
*
* @return the page size
*/
int getPageSize();
/**
* Gets the page.
*
* @return the page
*/
int getPage();
}
/*
* Created on 30. 10. 2016 7:32:25
*
*/
package com.jh.boot.web.list;
/**
* The Enum SortTrend.
*
* @author Jan Hrabal
*/
public enum SortTrend {
/** The ascending. */
ASCENDING("asc"),
/** The descending. */
DESCENDING("desc");
private String trend;
private SortTrend(String trend) {
this.trend = trend;
}
public String getTrend() {
return trend;
}
@Override
public String toString() {
return trend;
}
public static SortTrend parse(String s) {
for (SortTrend st : values()) {
if (st.trend.equalsIgnoreCase(s) || st.name().equalsIgnoreCase(s)) {
return st;
}
}
return null;
}
}
package com.jh.boot.web.list;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import com.jh.boot.utils.Utils;
/**
* The Class SortingArgumentResolver.
*/
public class SortingArgumentResolver implements HandlerMethodArgumentResolver {
/*
const ps = headers["x-paging-page"] * 1;
const psize = headers["x-paging-pagesize"] * 1;
const pcs = headers["x-paging-pagescount"] * 1;
*/
/** The Constant PAGING_PAGE. */
private static final String PAGING_PAGE = "X-Paging-Page";
/** The Constant PAGING_PAGE_SIZE. */
private static final String PAGING_PAGE_SIZE = "X-Paging-PageSize";
// private static final String PAGING_PAGES_COUNT = "X-Paging-PagesCount";
/**
* @param parameter
* @return
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter)
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(PagingInfo.class);
}
/**
* @param parameter
* @param mavContainer
* @param webRequest
* @param binderFactory
* @return
* @throws Exception
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory)
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Integer page = Utils.parseInt(webRequest.getHeader(PAGING_PAGE), 0);
Integer pageSize = Utils.parseInt(webRequest.getHeader(PAGING_PAGE_SIZE), 0);
return new DefaultPagingInfo(page, pageSize);
}
}
\ No newline at end of file
/*
* Created on 13. 10. 2016 17:11:34
*
*/
package com.jh.boot.web.list;
/**
* TODO.
*
* @author Jan Hrabal
*/
public interface SortingInfo {
/**
* Gets the field.
*
* @return the field
*/
String getField();
/**
* Gets the trend.
*
* @return the trend
*/
SortTrend getTrend();
}
package com.jh.core.error;
import java.util.Collection;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
public class ApiException extends ResponseStatusException implements ErrorStatus, ErrorMessages {
private static final long serialVersionUID = 1L;
private ErrorMessage[] errors;
public ApiException(HttpStatus status, ErrorMessage...errorMessages) {
super(status);
this.errors = errorMessages;
}
public ApiException(HttpStatus status, Collection<ErrorMessage> errorMessages) {
super(status);
this.errors = errorMessages == null ? new ErrorMessage[0] : errorMessages.toArray(new ErrorMessage[0]);
}
public ApiException(HttpStatus status, String reason, ErrorMessage...errorMessages) {
super(status, reason);
this.errors = errorMessages;
}
public ApiException(HttpStatus status, String reason, Throwable cause, ErrorMessage...errorMessages) {
super(status, reason, cause);
this.errors = errorMessages;
}
@Override
public ErrorMessage[] getErrorMessages() {
return errors;
}
@Override
public HttpStatus getErrorStatus() {
return getStatus();
}
}
package com.jh.boot.web.error;
package com.jh.core.error;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
......@@ -8,20 +8,11 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
/**
* The Class RestResponseEntityExceptionHandler.
*/
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@ControllerAdvice
public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
/**
* Handle all.
*
* @param ex the ex
* @return the response entity
*/
@ExceptionHandler({ Exception.class })
@ExceptionHandler({ ApiException.class })
public ResponseEntity<Object> handleAll(Exception ex) {
ErrorMessage[] errors = null;
......
package com.jh.boot.web.error;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* The Class ErrorMessage.
*/
public class ErrorMessage {
public static final String CODE_VALUE_REQUIRED = "VALUE_REQUIRED";
public static final String CODE_NOT_FOUND = "NOT_FOUND";
/** The field. */
private String field;
/** The code. */
private String code;
/** The message. */
@JsonProperty("msg")
private String message;
private Object payload;
/**
* Instantiates a new error message.
*/
private ErrorMessage() {
}
/* builder methods */
/**
* Constructs error message with field, code and message .
*
* @param field the field
* @param code the code
* @param message the message
* @return the error message
*/
public static ErrorMessage withFieldCodeMessage(String field, String code, String message) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.code = code;
em.message = message;
return em;
}
/**
* Constructs error message with field, code and message .
*
* @param field the field
* @param message the message
* @return the error message
*/
public static ErrorMessage withFieldMessage(String field, String message) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.message = message;
return em;
}
/**
* Constructs error message with field and code .
*
* @param field the field
* @param code the code
* @return the error message
*/
public static ErrorMessage withFieldCode(String field, String code) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.code = code;
return em;
}
/**
* Constructs error message with code and message .
*
* @param code the code
* @param message the message
* @return the error message
*/
public static ErrorMessage withCodeMessage(String code, String message) {
ErrorMessage em = new ErrorMessage();
em.code = code;
em.message = message;
return em;
}
public static ErrorMessage withCodePayload(String code, Object payload) {
ErrorMessage em = new ErrorMessage();
em.code = code;
em.payload = payload;
return em;
}
public static ErrorMessage withFieldCodePayload(String field, String code, Object payload) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.code = code;
em.payload = payload;
return em;
}
public static ErrorMessage withFieldCodeMessagePayload(String field, String code, String message, Object payload) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.code = code;
em.payload = payload;
em.message = message;
return em;
}
public static ErrorMessage withMessagePayload(String message, Object payload) {
ErrorMessage em = new ErrorMessage();
em.payload = payload;
em.message = message;
return em;
}
public static ErrorMessage withFieldMessagePayload(String field, String message, Object payload) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.payload = payload;
em.message = message;
return em;
}
/**
* With message.
*
* @param message the message
* @return the error message
*/
public static ErrorMessage withMessage(String message) {
ErrorMessage em = new ErrorMessage();
em.message = message;
return em;
}
/**
* With code.
*
* @param code the code
* @return the error message
*/
public static ErrorMessage withCode(String code) {
ErrorMessage em = new ErrorMessage();
em.code = code;
return em;
}
/* getters */
/**
* Gets the field.
*
* @return the field
*/
public String getField() {
return field;
}
/**
* Gets the code.
*
* @return the code
*/
public String getCode() {
return code;
}
/**
* Gets the message.
*
* @return the message
*/
public String getMessage() {
return message;
}
public Object getPayload() {
return payload;
}
package com.jh.core.error;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* The Class ErrorMessage.
*/
public class ErrorMessage {
public static final String CODE_VALUE_REQUIRED = "VALUE_REQUIRED";
public static final String CODE_NOT_FOUND = "NOT_FOUND";
/** The field. */
private String field;
/** The code. */
private String code;
/** The message. */
@JsonProperty("msg")
private String message;
private Object payload;
/**
* Instantiates a new error message.
*/
private ErrorMessage() {
}
/* builder methods */
/**
* Constructs error message with field, code and message .
*
* @param field the field
* @param code the code
* @param message the message
* @return the error message
*/
public static ErrorMessage withFieldCodeMessage(String field, String code, String message) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.code = code;
em.message = message;
return em;
}
/**
* Constructs error message with field, code and message .
*
* @param field the field
* @param message the message
* @return the error message
*/
public static ErrorMessage withFieldMessage(String field, String message) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.message = message;
return em;
}
/**
* Constructs error message with field and code .
*
* @param field the field
* @param code the code
* @return the error message
*/
public static ErrorMessage withFieldCode(String field, String code) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.code = code;
return em;
}
/**
* Constructs error message with code and message .
*
* @param code the code
* @param message the message
* @return the error message
*/
public static ErrorMessage withCodeMessage(String code, String message) {
ErrorMessage em = new ErrorMessage();
em.code = code;
em.message = message;
return em;
}
public static ErrorMessage withCodePayload(String code, Object payload) {
ErrorMessage em = new ErrorMessage();
em.code = code;
em.payload = payload;
return em;
}
public static ErrorMessage withFieldCodePayload(String field, String code, Object payload) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.code = code;
em.payload = payload;
return em;
}
public static ErrorMessage withFieldCodeMessagePayload(String field, String code, String message, Object payload) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.code = code;
em.payload = payload;
em.message = message;
return em;
}
public static ErrorMessage withMessagePayload(String message, Object payload) {
ErrorMessage em = new ErrorMessage();
em.payload = payload;
em.message = message;
return em;
}
public static ErrorMessage withFieldMessagePayload(String field, String message, Object payload) {
ErrorMessage em = new ErrorMessage();
em.field = field;
em.payload = payload;
em.message = message;
return em;
}
/**
* With message.
*
* @param message the message
* @return the error message
*/
public static ErrorMessage withMessage(String message) {
ErrorMessage em = new ErrorMessage();
em.message = message;
return em;
}
/**
* With code.
*
* @param code the code
* @return the error message
*/
public static ErrorMessage withCode(String code) {
ErrorMessage em = new ErrorMessage();
em.code = code;
return em;
}
/* getters */
/**
* Gets the field.
*
* @return the field
*/
public String getField() {
return field;
}
/**
* Gets the code.
*
* @return the code
*/
public String getCode() {
return code;
}
/**
* Gets the message.
*
* @return the message
*/
public String getMessage() {
return message;
}
public Object getPayload() {
return payload;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment