diff --git a/layer-api/src/main/java/org/layer/config/ObjectMapperConfig.java b/layer-api/src/main/java/org/layer/config/ObjectMapperConfig.java new file mode 100644 index 00000000..7047bd05 --- /dev/null +++ b/layer-api/src/main/java/org/layer/config/ObjectMapperConfig.java @@ -0,0 +1,29 @@ +package org.layer.config; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ObjectMapperConfig { + + @Bean + public ObjectMapper objectMapper(){ + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new Jdk8Module()); + objectMapper.registerModule(new JavaTimeModule()); + + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + // 카멜 케이스 + objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.LowerCamelCaseStrategy()); + return objectMapper; + + } +} \ No newline at end of file diff --git a/layer-api/src/main/java/org/layer/filter/LoggerFilter.java b/layer-api/src/main/java/org/layer/filter/LoggerFilter.java new file mode 100644 index 00000000..67e72978 --- /dev/null +++ b/layer-api/src/main/java/org/layer/filter/LoggerFilter.java @@ -0,0 +1,65 @@ +package org.layer.filter; + +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.util.ContentCachingRequestWrapper; +import org.springframework.web.util.ContentCachingResponseWrapper; + +import java.io.IOException; + +@Component +@Slf4j +public class LoggerFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + var req = new ContentCachingRequestWrapper((HttpServletRequest) request); + var res = new ContentCachingResponseWrapper((HttpServletResponse) response); + + chain.doFilter(req,res); + + // request 정보 + var headerNames = req.getHeaderNames(); + var headerValues = new StringBuilder(); + + headerNames.asIterator().forEachRemaining(headerKey -> { + var headerValue = req.getHeader(headerKey); + + headerValues + .append("[") + .append(headerKey) + .append(" : ") + .append(headerValue) + .append(" , ") + .append("] "); + }); + var requestBody = new String(req.getContentAsByteArray()); + var uri = req.getRequestURI(); + var method = req.getMethod(); + + log.info("[REQUEST] uri : {} , method : {} , header : {} , body : {}" ,uri,method, headerValues, requestBody); + + // response + var responseHeaderValues = new StringBuilder(); + res.getHeaderNames().forEach(headerKey -> { + var headerValue = res.getHeader(headerKey); + responseHeaderValues + .append("[") + .append(headerKey) + .append(" : ") + .append(headerValue) + .append(" ,") + .append("] "); + }); + + // var responseBody = new String(res.getContentAsByteArray()); + + log.info("[RESPONSE] uri : {} , method : {} , header : {} , body : {}",uri,method, responseHeaderValues); + + res.copyBodyToResponse(); + } +} + diff --git a/layer-domain/src/main/java/org/layer/domain/BaseEntity.java b/layer-domain/src/main/java/org/layer/domain/BaseEntity.java new file mode 100644 index 00000000..8eb74dba --- /dev/null +++ b/layer-domain/src/main/java/org/layer/domain/BaseEntity.java @@ -0,0 +1,25 @@ +package org.layer.domain; + +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import java.time.LocalDateTime; + +@MappedSuperclass +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @CreatedDate + private LocalDateTime createdAt; + + @LastModifiedDate + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/layer-domain/src/main/java/org/layer/domain/block/converter/BlockStyleConverter.java b/layer-domain/src/main/java/org/layer/domain/block/converter/BlockStyleConverter.java new file mode 100644 index 00000000..0607ba2a --- /dev/null +++ b/layer-domain/src/main/java/org/layer/domain/block/converter/BlockStyleConverter.java @@ -0,0 +1,26 @@ +package org.layer.domain.block.converter; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +import org.layer.domain.block.enums.BlockType; + + +import java.util.stream.Stream; + +@Converter +public class BlockStyleConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(BlockType blockType) { + return blockType.getStyle(); + } + + @Override + public BlockType convertToEntityAttribute(String blockStyle) { + if(blockStyle == null){ + return null; + } + return Stream.of(BlockType.values()).filter(t -> t.getStyle().equals(blockStyle)).findFirst() + .orElseThrow(IllegalArgumentException::new); + } +} diff --git a/layer-domain/src/main/java/org/layer/domain/block/entity/Block.java b/layer-domain/src/main/java/org/layer/domain/block/entity/Block.java new file mode 100644 index 00000000..cfaf4317 --- /dev/null +++ b/layer-domain/src/main/java/org/layer/domain/block/entity/Block.java @@ -0,0 +1,36 @@ +package org.layer.domain.block.entity; + +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import org.layer.domain.BaseEntity; +import org.layer.domain.block.converter.BlockStyleConverter; +import org.layer.domain.block.enums.BlockType; +import org.layer.domain.blockOption.entity.BlockOption; + +import java.util.HashSet; +import java.util.Set; + +@Getter +@Entity +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Block extends BaseEntity { + + /** + * Form RelationId + */ + @NotNull + private Long formId; + + private String label; + + @Column(length = 20) + @NotNull + @Convert(converter = BlockStyleConverter.class) + private BlockType style; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "block", cascade = CascadeType.ALL, orphanRemoval = true) + private Set options = new HashSet<>(); +} diff --git a/layer-domain/src/main/java/org/layer/domain/block/enums/BlockType.java b/layer-domain/src/main/java/org/layer/domain/block/enums/BlockType.java new file mode 100644 index 00000000..5b8e0c74 --- /dev/null +++ b/layer-domain/src/main/java/org/layer/domain/block/enums/BlockType.java @@ -0,0 +1,35 @@ +package org.layer.domain.block.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum BlockType { + /** + * 질문(입력) 블록 종류 + * 1. 짧은 인풋 + * 2. 마크다운 + * 3. 레인저 + * 4. 콤보 박스 + * 5. 카드 + * 6. 숫자 인풋 + * + * 질문 블록 중 이산적인 블록 종류 + * 1. 레인저( 숫자 ) + * 2. 콤보 박스 + * 3. 카드 + * + */ + + PLAIN_TEXT("짧은 입력","plain_text","single"), + MARKDOWN("마크다운 입력","markdown","single"), + RANGER("범위 지정","range","multi"), + COMBOBOX("콤보 박스","combobox","multi"), + CARD("카드 선택 입력","card","multi"), + NUMBER("숫자 입력","number","single"); + + private String description; + private String style; + private String type; +} diff --git a/layer-domain/src/main/java/org/layer/domain/blockOption/entity/BlockOption.java b/layer-domain/src/main/java/org/layer/domain/blockOption/entity/BlockOption.java new file mode 100644 index 00000000..d8291454 --- /dev/null +++ b/layer-domain/src/main/java/org/layer/domain/blockOption/entity/BlockOption.java @@ -0,0 +1,29 @@ +package org.layer.domain.blockOption.entity; + +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.layer.domain.BaseEntity; +import org.layer.domain.block.entity.Block; + +@Entity +@Table(name= "block_option", uniqueConstraints = { + @UniqueConstraint(columnNames = {"block_id", "value"}) +}) +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class BlockOption extends BaseEntity { + + private String label; + + @NotNull + private String value; + + @ManyToOne + @JoinColumn( name = "block_id") + private Block block; +} \ No newline at end of file diff --git a/layer-domain/src/main/java/org/layer/domain/form/converter/FormPublishedByConverter.java b/layer-domain/src/main/java/org/layer/domain/form/converter/FormPublishedByConverter.java new file mode 100644 index 00000000..82905a02 --- /dev/null +++ b/layer-domain/src/main/java/org/layer/domain/form/converter/FormPublishedByConverter.java @@ -0,0 +1,25 @@ +package org.layer.domain.form.converter; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +import org.layer.domain.form.enums.FormPublishedBy; + +import java.util.stream.Stream; + +@Converter +public class FormPublishedByConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(FormPublishedBy formPublishType) { + return formPublishType.getCode(); + } + + @Override + public FormPublishedBy convertToEntityAttribute(final String code) { + if(code == null){ + return null; + } + return Stream.of(FormPublishedBy.values()).filter(t -> t.getCode().equals(code)).findFirst() + .orElseThrow(IllegalArgumentException::new); + } +} diff --git a/layer-domain/src/main/java/org/layer/domain/form/entity/Form.java b/layer-domain/src/main/java/org/layer/domain/form/entity/Form.java index e04e0d0e..12618c32 100644 --- a/layer-domain/src/main/java/org/layer/domain/form/entity/Form.java +++ b/layer-domain/src/main/java/org/layer/domain/form/entity/Form.java @@ -1,27 +1,32 @@ package org.layer.domain.form.entity; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; +import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; +import org.hibernate.annotations.ColumnDefault; +import org.layer.domain.BaseEntity; +import org.layer.domain.form.converter.FormPublishedByConverter; +import org.layer.domain.form.enums.FormPublishedBy; + @Getter @Entity +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Form { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; +public class Form extends BaseEntity { private Long memberId; @NotNull private String title; + @Column(length = 10) + @ColumnDefault("1") + @Convert(converter = FormPublishedByConverter.class) + @NotNull + private FormPublishedBy formPublishedBy; + private String introduction; } diff --git a/layer-domain/src/main/java/org/layer/domain/form/enums/FormPublishedBy.java b/layer-domain/src/main/java/org/layer/domain/form/enums/FormPublishedBy.java new file mode 100644 index 00000000..58151fb3 --- /dev/null +++ b/layer-domain/src/main/java/org/layer/domain/form/enums/FormPublishedBy.java @@ -0,0 +1,16 @@ +package org.layer.domain.form.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum FormPublishedBy { + + ADMIN("관리자","0"), + PERSONAL("개인","1"); + ; + private String description; + private String code; + +}